html/api_usage.ipynb0000664000175000017500000014204313743770165014747 0ustar priesgopriesgo{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Programmatic usage" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "from neofox.model.conversion import ModelConverter\n", "from neofox.model.validation import ModelValidator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a neoantigen" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "from neofox.model.neoantigen import Neoantigen, Transcript, Mutation" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [], "source": [ "transcript = Transcript(assembly=\"hg19\", gene=\"VCAN\", identifier=\"uc003kii.3\")\n", "mutation = Mutation(position=1007, wild_type_aminoacid=\"I\", mutated_aminoacid=\"T\", left_flanking_region=\"DEVLGEPSQDILV\", right_flanking_region=\"DQTRLEATISPET\")\n", "neoantigen = Neoantigen(transcript=transcript, mutation=mutation, patient_identifier=\"P123\", rna_expression=0.519506894, rna_variant_allele_frequency=0.857142857, dna_variant_allele_frequency=0.294573643)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Validate a neoantigen" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"identifier\": \"jETwpX0R9iEiQz2SMpHkPQ==\",\n", " \"patientIdentifier\": \"P123\",\n", " \"transcript\": {\n", " \"identifier\": \"uc003kii.3\",\n", " \"assembly\": \"hg19\",\n", " \"gene\": \"VCAN\"\n", " },\n", " \"mutation\": {\n", " \"position\": 1007,\n", " \"wildTypeXmer\": \"DEVLGEPSQDILVIDQTRLEATISPET\",\n", " \"wildTypeAminoacid\": \"I\",\n", " \"mutatedXmer\": \"DEVLGEPSQDILVTDQTRLEATISPET\",\n", " \"mutatedAminoacid\": \"T\",\n", " \"leftFlankingRegion\": \"DEVLGEPSQDILV\",\n", " \"sizeLeftFlankingRegion\": 13,\n", " \"rightFlankingRegion\": \"DQTRLEATISPET\",\n", " \"sizeRightFlankingRegion\": 13\n", " },\n", " \"rnaExpression\": 0.519506894,\n", " \"dnaVariantAlleleFrequency\": 0.294573643,\n", " \"rnaVariantAlleleFrequency\": 0.857142857\n", "}\n" ] } ], "source": [ "validated_neoantigen = ModelValidator.validate_neoantigen(neoantigen=neoantigen)\n", "print(validated_neoantigen.to_json(indent=2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a patient" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "from neofox.model.neoantigen import Patient" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# define the MHC I alleles of the patient and parse them into the object representation\n", "mhc1 = ModelConverter.parse_mhc1_alleles([\"HLA-A*01:01:02:03N\", \"HLA-A*01:02:02:03N\", \"HLA-B*01:01:02:03N\", \"HLA-B*01:01:02:04N\", \"HLA-C*01:01\"])" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"zygosity\": \"HETEROZYGOUS\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-A*01:01:02:03N\",\n", " \"name\": \"HLA-A*01:01\",\n", " \"gene\": \"A\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " },\n", " {\n", " \"fullName\": \"HLA-A*01:02:02:03N\",\n", " \"name\": \"HLA-A*01:02\",\n", " \"gene\": \"A\",\n", " \"group\": \"01\",\n", " \"protein\": \"02\"\n", " }\n", " ]\n", "}\n" ] } ], "source": [ "# MHC allele names will be normalised into 4 digits names\n", "print(mhc1[0].to_json(indent=2))" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "# define the MHC II alleles of the patient and parse them into the object representation\n", "mhc2 = ModelConverter.parse_mhc2_alleles([\"HLA-DPA1*01:01\", \"HLA-DPA1*01:02\", \"HLA-DPB1*01:01\", \"HLA-DPB1*01:01\", \"HLA-DRB1*01:01\", \"HLA-DRB1*01:01\"])" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'NoneType' object has no attribute '_serialized_on_wire'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmhc2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_json\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindent\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/src/addannot/venv/lib/python3.6/site-packages/betterproto/__init__.py\u001b[0m in \u001b[0;36mto_json\u001b[0;34m(self, indent)\u001b[0m\n\u001b[1;32m 925\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mto_json\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mindent\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mUnion\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 926\u001b[0m \u001b[0;34m\"\"\"Returns the encoded JSON representation of this message instance.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 927\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mjson\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdumps\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mindent\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mindent\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 928\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 929\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mfrom_json\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mT\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mUnion\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbytes\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mT\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/src/addannot/venv/lib/python3.6/site-packages/betterproto/__init__.py\u001b[0m in \u001b[0;36mto_dict\u001b[0;34m(self, casing, include_default_values)\u001b[0m\n\u001b[1;32m 827\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 828\u001b[0m \u001b[0;31m# Convert each item.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 829\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasing\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 830\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mv\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 831\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcased_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/src/addannot/venv/lib/python3.6/site-packages/betterproto/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 827\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 828\u001b[0m \u001b[0;31m# Convert each item.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 829\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasing\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 830\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mv\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 831\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcased_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/src/addannot/venv/lib/python3.6/site-packages/betterproto/__init__.py\u001b[0m in \u001b[0;36mto_dict\u001b[0;34m(self, casing, include_default_values)\u001b[0m\n\u001b[1;32m 831\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcased_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 832\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 833\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_serialized_on_wire\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 834\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcased_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasing\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 835\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmeta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mproto_type\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"map\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute '_serialized_on_wire'" ] } ], "source": [ "print(mhc2[0].to_json(indent=2))" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Mhc2(name=, genes=[Mhc2Gene(name=, zygosity=, alleles=[MhcAllele(full_name='HLA-DRB1*01:01', name='HLA-DRB1*01:01', gene='DRB1', group='01', protein='01')])], isoforms=[Mhc2Isoform(name='HLA-DRB1*01:01', alpha_chain=None, beta_chain=MhcAllele(full_name='HLA-DRB1*01:01', name='HLA-DRB1*01:01', gene='DRB1', group='01', protein='01'))])" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mhc2[0]" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "patient = Patient(identifier=\"P123\", is_rna_available=True, mhc1=mhc1, mhc2=mhc2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Validate a patient" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "from neofox.model.validation import ModelValidator" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "validated_patient = ModelValidator.validate_patient(patient)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run Neofox" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject\n", " return f(*args, **kwds)\n", "/usr/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject\n", " return f(*args, **kwds)\n", "/usr/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject\n", " return f(*args, **kwds)\n" ] } ], "source": [ "from neofox.neofox import NeoFox" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[I 201020 22:58:59 neofox:80] Loading data...\n", "/home/priesgo/src/addannot/venv/lib/python3.6/site-packages/distributed/node.py:173: UserWarning: Port 8787 is already in use.\n", "Perhaps you already have a cluster running?\n", "Hosting the HTTP server on port 46855 instead\n", " http_address[\"port\"], self.http_server.port\n", "[I 201020 22:59:00 references:141] Reference genome folder: /home/priesgo/neofox_install/reference_data_5\n", "[I 201020 22:59:00 references:142] Resources\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/netmhc2pan_available_alleles.txt\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/netmhcpan_available_alleles.txt\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/Homo_sapiens.fa\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb/IEDB.fasta\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb/iedb_blast_db.phr\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb/iedb_blast_db.pin\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb/iedb_blast_db.psq\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/Homo_sapiens.fa\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.phr\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.pin\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.pog\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.psd\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.psi\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.psq\n", "[I 201020 22:59:00 neofox:69] Data loaded\n", "[I 201020 22:59:00 neofox:109] Starting NeoFox annotations...\n", "[D 201020 22:59:00 neofox:115] Neoantigen: {\n", " \"identifier\": \"jETwpX0R9iEiQz2SMpHkPQ==\",\n", " \"patientIdentifier\": \"P123\",\n", " \"transcript\": {\n", " \"identifier\": \"uc003kii.3\",\n", " \"assembly\": \"hg19\",\n", " \"gene\": \"VCAN\"\n", " },\n", " \"mutation\": {\n", " \"position\": 1007,\n", " \"wildTypeXmer\": \"DEVLGEPSQDILVIDQTRLEATISPET\",\n", " \"wildTypeAminoacid\": \"I\",\n", " \"mutatedXmer\": \"DEVLGEPSQDILVTDQTRLEATISPET\",\n", " \"mutatedAminoacid\": \"T\",\n", " \"leftFlankingRegion\": \"DEVLGEPSQDILV\",\n", " \"sizeLeftFlankingRegion\": 13,\n", " \"rightFlankingRegion\": \"DQTRLEATISPET\",\n", " \"sizeRightFlankingRegion\": 13\n", " },\n", " \"rnaExpression\": 0.519506894,\n", " \"dnaVariantAlleleFrequency\": 0.294573643,\n", " \"rnaVariantAlleleFrequency\": 0.857142857\n", " }\n", "[D 201020 22:59:00 neofox:116] Patient: {\n", " \"identifier\": \"P123\",\n", " \"isRnaAvailable\": true,\n", " \"mhc1\": [\n", " {\n", " \"zygosity\": \"HETEROZYGOUS\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-A*01:01:02:03N\",\n", " \"name\": \"HLA-A*01:01\",\n", " \"gene\": \"A\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " },\n", " {\n", " \"fullName\": \"HLA-A*01:02:02:03N\",\n", " \"name\": \"HLA-A*01:02\",\n", " \"gene\": \"A\",\n", " \"group\": \"01\",\n", " \"protein\": \"02\"\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"B\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-B*01:01:02:04N\",\n", " \"name\": \"HLA-B*01:01\",\n", " \"gene\": \"B\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"C\",\n", " \"zygosity\": \"HEMIZYGOUS\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-C*01:01\",\n", " \"name\": \"HLA-C*01:01\",\n", " \"gene\": \"C\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " ]\n", " }\n", " ],\n", " \"mhc2\": [\n", " {\n", " \"genes\": [\n", " {\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-DRB1*01:01\",\n", " \"name\": \"HLA-DRB1*01:01\",\n", " \"gene\": \"DRB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " ]\n", " }\n", " ],\n", " \"isoforms\": [\n", " {\n", " \"name\": \"HLA-DRB1*01:01\",\n", " \"betaChain\": {\n", " \"fullName\": \"HLA-DRB1*01:01\",\n", " \"name\": \"HLA-DRB1*01:01\",\n", " \"gene\": \"DRB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"DP\",\n", " \"genes\": [\n", " {\n", " \"name\": \"DPA1\",\n", " \"zygosity\": \"HETEROZYGOUS\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-DPA1*01:01\",\n", " \"name\": \"HLA-DPA1*01:01\",\n", " \"gene\": \"DPA1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " },\n", " {\n", " \"fullName\": \"HLA-DPA1*01:02\",\n", " \"name\": \"HLA-DPA1*01:02\",\n", " \"gene\": \"DPA1\",\n", " \"group\": \"01\",\n", " \"protein\": \"02\"\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"DPB1\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-DPB1*01:01\",\n", " \"name\": \"HLA-DPB1*01:01\",\n", " \"gene\": \"DPB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " ]\n", " }\n", " ],\n", " \"isoforms\": [\n", " {\n", " \"name\": \"HLA-DPA1*01:01-DPB1*01:01\",\n", " \"alphaChain\": {\n", " \"fullName\": \"HLA-DPA1*01:01\",\n", " \"name\": \"HLA-DPA1*01:01\",\n", " \"gene\": \"DPA1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " },\n", " \"betaChain\": {\n", " \"fullName\": \"HLA-DPB1*01:01\",\n", " \"name\": \"HLA-DPB1*01:01\",\n", " \"gene\": \"DPB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " },\n", " {\n", " \"name\": \"HLA-DPA1*01:02-DPB1*01:01\",\n", " \"alphaChain\": {\n", " \"fullName\": \"HLA-DPA1*01:02\",\n", " \"name\": \"HLA-DPA1*01:02\",\n", " \"gene\": \"DPA1\",\n", " \"group\": \"01\",\n", " \"protein\": \"02\"\n", " },\n", " \"betaChain\": {\n", " \"fullName\": \"HLA-DPB1*01:01\",\n", " \"name\": \"HLA-DPB1*01:01\",\n", " \"gene\": \"DPB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"DQ\",\n", " \"genes\": [\n", " {\n", " \"name\": \"DQA1\",\n", " \"zygosity\": \"LOSS\"\n", " },\n", " {\n", " \"name\": \"DQB1\",\n", " \"zygosity\": \"LOSS\"\n", " }\n", " ]\n", " }\n", " ]\n", " }\n", "[I 201020 22:59:07 neofox:123] Elapsed time for annotating 1 neoantigens 7 seconds\n" ] } ], "source": [ "annotations = NeoFox(neoantigens=[validated_neoantigen], patients=[validated_patient], patient_id=\"P123\", num_cpus=2).get_annotations()" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[NeoantigenAnnotations(neoantigen_identifier='jETwpX0R9iEiQz2SMpHkPQ==', annotations=[Annotation(name='Expression_mutated_transcript', value='0.44529'), Annotation(name='mutation_not_found_in_proteome', value='1'), Annotation(name='Best_rank_MHCI_score', value='0.4384'), Annotation(name='Best_rank_MHCI_score_epitope', value='VTDQTRLEA'), Annotation(name='Best_rank_MHCI_score_allele', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_score', value='874.8'), Annotation(name='Best_affinity_MHCI_epitope', value='VTDQTRLEA'), Annotation(name='Best_affinity_MHCI_allele', value='HLA-A*01:01'), Annotation(name='Best_rank_MHCI_9mer_score', value='0.4384'), Annotation(name='Best_rank_MHCI_9mer_epitope', value='VTDQTRLEA'), Annotation(name='Best_rank_MHCI_9mer_allele', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_9mer_score', value='874.8'), Annotation(name='Best_affinity_MHCI_9mer_allele', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_9mer_epitope', value='VTDQTRLEA'), Annotation(name='Best_affinity_MHCI_score_WT', value='6296.8'), Annotation(name='Best_affinity_MHCI_epitope_WT', value='VIDQTRLEA'), Annotation(name='Best_affinity_MHCI_allele_WT', value='HLA-A*01:01'), Annotation(name='Best_rank_MHCI_score_WT', value='1.8897'), Annotation(name='Best_rank_MHCI_score_epitope_WT', value='VIDQTRLEA'), Annotation(name='Best_rank_MHCI_score_allele_WT', value='HLA-A*01:01'), Annotation(name='Best_rank_MHCI_9mer_score_WT', value='1.8897'), Annotation(name='Best_rank_MHCI_9mer_epitope_WT', value='VIDQTRLEA'), Annotation(name='Best_rank_MHCI_9mer_allele_WT', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_9mer_score_WT', value='6296.8'), Annotation(name='Best_affinity_MHCI_9mer_allele_WT', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_9mer_epitope_WT', value='VIDQTRLEA'), Annotation(name='Generator_rate', value='0'), Annotation(name='PHBR-I', value='NA'), Annotation(name='Best_affinity_MHCI_9mer_position_mutation', value='2'), Annotation(name='Best_rank_MHCII_score', value='65'), Annotation(name='Best_rank_MHCII_score_epitope', value='SQDILVTDQTRLEAT'), Annotation(name='Best_rank_MHCII_score_allele', value='DRB1_0101'), Annotation(name='Best_affinity_MHCII_score', value='647.81'), Annotation(name='Best_affinity_MHCII_epitope', value='SQDILVTDQTRLEAT'), Annotation(name='Best_affinity_MHCII_allele', value='DRB1_0101'), Annotation(name='Best_rank_MHCII_score_WT', value='46'), Annotation(name='Best_rank_MHCII_score_epitope_WT', value='SQDILVIDQTRLEAT'), Annotation(name='Best_rank_MHCII_score_allele_WT', value='DRB1_0101'), Annotation(name='Best_affinity_MHCII_score_WT', value='269.19'), Annotation(name='Best_affinity_MHCII_epitope_WT', value='SQDILVIDQTRLEAT'), Annotation(name='Best_affinity_MHCII_allele_WT', value='DRB1_0101'), Annotation(name='PHBR-II', value='NA'), Annotation(name='Amplitude_MHCI_affinity_9mer', value='2.4915'), Annotation(name='Amplitude_MHCI_affinity', value='2.4915'), Annotation(name='Pathogensimiliarity_MHCI_affinity_9mer', value='0'), Annotation(name='Recognition_Potential_MHCI_affinity_9mer', value='NA'), Annotation(name='DAI_MHCI_affinity_cutoff500nM', value='NA'), Annotation(name='CDN_MHCI', value='0'), Annotation(name='ADN_MHCI', value='0'), Annotation(name='CDN_MHCII', value='0'), Annotation(name='ADN_MHCII', value='0'), Annotation(name='Tcell_predictor_score_cutoff500nM', value='NA'), Annotation(name='Improved_Binder_MHCI', value='1'), Annotation(name='Selfsimilarity_MHCI_conserved_binder', value='NA'), Annotation(name='Number_of_mismatches_MCHI', value='1'), Annotation(name='Priority_score', value='0.09596'), Annotation(name='Neoag_immunogenicity', value='NA'), Annotation(name='IEDB_Immunogenicity_MHCI_cutoff500nM', value='NA'), Annotation(name='MixMHCpred_best_peptide', value='NA'), Annotation(name='MixMHCpred_best_score', value='NA'), Annotation(name='MixMHCpred_best_rank', value='NA'), Annotation(name='MixMHCpred_best_allele', value='NA'), Annotation(name='MixMHC2pred_best_peptide', value='DEVLGEPSQDILVT'), Annotation(name='MixMHC2pred_best_rank', value='2.818'), Annotation(name='MixMHC2pred_best_allele', value='DRB1_01_01'), Annotation(name='Dissimilarity_MHCI_cutoff500nM', value='NA'), Annotation(name='vaxrank_binding_score', value='0.0322'), Annotation(name='vaxrank_total_score', value='0.01434')], annotator='Neofox', annotator_version='0.4.0.dev1', timestamp='20201020225902062657', resources_hash='')]" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "annotations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Transform the annotations into a data frame" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [], "source": [ "annotations_ts = ModelConverter.annotations2tall_skinny_table(neoantigen_annotations=annotations)" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namevalueneoantigen_identifier
0Expression_mutated_transcript0.44529jETwpX0R9iEiQz2SMpHkPQ==
1mutation_not_found_in_proteome1jETwpX0R9iEiQz2SMpHkPQ==
2Best_rank_MHCI_score0.4384jETwpX0R9iEiQz2SMpHkPQ==
3Best_rank_MHCI_score_epitopeVTDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
4Best_rank_MHCI_score_alleleHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
5Best_affinity_MHCI_score874.8jETwpX0R9iEiQz2SMpHkPQ==
6Best_affinity_MHCI_epitopeVTDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
7Best_affinity_MHCI_alleleHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
8Best_rank_MHCI_9mer_score0.4384jETwpX0R9iEiQz2SMpHkPQ==
9Best_rank_MHCI_9mer_epitopeVTDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
10Best_rank_MHCI_9mer_alleleHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
11Best_affinity_MHCI_9mer_score874.8jETwpX0R9iEiQz2SMpHkPQ==
12Best_affinity_MHCI_9mer_alleleHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
13Best_affinity_MHCI_9mer_epitopeVTDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
14Best_affinity_MHCI_score_WT6296.8jETwpX0R9iEiQz2SMpHkPQ==
15Best_affinity_MHCI_epitope_WTVIDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
16Best_affinity_MHCI_allele_WTHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
17Best_rank_MHCI_score_WT1.8897jETwpX0R9iEiQz2SMpHkPQ==
18Best_rank_MHCI_score_epitope_WTVIDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
19Best_rank_MHCI_score_allele_WTHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
20Best_rank_MHCI_9mer_score_WT1.8897jETwpX0R9iEiQz2SMpHkPQ==
21Best_rank_MHCI_9mer_epitope_WTVIDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
22Best_rank_MHCI_9mer_allele_WTHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
23Best_affinity_MHCI_9mer_score_WT6296.8jETwpX0R9iEiQz2SMpHkPQ==
24Best_affinity_MHCI_9mer_allele_WTHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
25Best_affinity_MHCI_9mer_epitope_WTVIDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
26Generator_rate0jETwpX0R9iEiQz2SMpHkPQ==
28Best_affinity_MHCI_9mer_position_mutation2jETwpX0R9iEiQz2SMpHkPQ==
29Best_rank_MHCII_score65jETwpX0R9iEiQz2SMpHkPQ==
30Best_rank_MHCII_score_epitopeSQDILVTDQTRLEATjETwpX0R9iEiQz2SMpHkPQ==
31Best_rank_MHCII_score_alleleDRB1_0101jETwpX0R9iEiQz2SMpHkPQ==
32Best_affinity_MHCII_score647.81jETwpX0R9iEiQz2SMpHkPQ==
33Best_affinity_MHCII_epitopeSQDILVTDQTRLEATjETwpX0R9iEiQz2SMpHkPQ==
34Best_affinity_MHCII_alleleDRB1_0101jETwpX0R9iEiQz2SMpHkPQ==
35Best_rank_MHCII_score_WT46jETwpX0R9iEiQz2SMpHkPQ==
36Best_rank_MHCII_score_epitope_WTSQDILVIDQTRLEATjETwpX0R9iEiQz2SMpHkPQ==
37Best_rank_MHCII_score_allele_WTDRB1_0101jETwpX0R9iEiQz2SMpHkPQ==
38Best_affinity_MHCII_score_WT269.19jETwpX0R9iEiQz2SMpHkPQ==
39Best_affinity_MHCII_epitope_WTSQDILVIDQTRLEATjETwpX0R9iEiQz2SMpHkPQ==
40Best_affinity_MHCII_allele_WTDRB1_0101jETwpX0R9iEiQz2SMpHkPQ==
42Amplitude_MHCI_affinity_9mer2.4915jETwpX0R9iEiQz2SMpHkPQ==
43Amplitude_MHCI_affinity2.4915jETwpX0R9iEiQz2SMpHkPQ==
44Pathogensimiliarity_MHCI_affinity_9mer0jETwpX0R9iEiQz2SMpHkPQ==
47CDN_MHCI0jETwpX0R9iEiQz2SMpHkPQ==
48ADN_MHCI0jETwpX0R9iEiQz2SMpHkPQ==
49CDN_MHCII0jETwpX0R9iEiQz2SMpHkPQ==
50ADN_MHCII0jETwpX0R9iEiQz2SMpHkPQ==
52Improved_Binder_MHCI1jETwpX0R9iEiQz2SMpHkPQ==
54Number_of_mismatches_MCHI1jETwpX0R9iEiQz2SMpHkPQ==
55Priority_score0.09596jETwpX0R9iEiQz2SMpHkPQ==
62MixMHC2pred_best_peptideDEVLGEPSQDILVTjETwpX0R9iEiQz2SMpHkPQ==
63MixMHC2pred_best_rank2.818jETwpX0R9iEiQz2SMpHkPQ==
64MixMHC2pred_best_alleleDRB1_01_01jETwpX0R9iEiQz2SMpHkPQ==
66vaxrank_binding_score0.0322jETwpX0R9iEiQz2SMpHkPQ==
67vaxrank_total_score0.01434jETwpX0R9iEiQz2SMpHkPQ==
\n", "
" ], "text/plain": [ " name value neoantigen_identifier\n", "0 Expression_mutated_transcript 0.44529 jETwpX0R9iEiQz2SMpHkPQ==\n", "1 mutation_not_found_in_proteome 1 jETwpX0R9iEiQz2SMpHkPQ==\n", "2 Best_rank_MHCI_score 0.4384 jETwpX0R9iEiQz2SMpHkPQ==\n", "3 Best_rank_MHCI_score_epitope VTDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "4 Best_rank_MHCI_score_allele HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "5 Best_affinity_MHCI_score 874.8 jETwpX0R9iEiQz2SMpHkPQ==\n", "6 Best_affinity_MHCI_epitope VTDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "7 Best_affinity_MHCI_allele HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "8 Best_rank_MHCI_9mer_score 0.4384 jETwpX0R9iEiQz2SMpHkPQ==\n", "9 Best_rank_MHCI_9mer_epitope VTDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "10 Best_rank_MHCI_9mer_allele HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "11 Best_affinity_MHCI_9mer_score 874.8 jETwpX0R9iEiQz2SMpHkPQ==\n", "12 Best_affinity_MHCI_9mer_allele HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "13 Best_affinity_MHCI_9mer_epitope VTDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "14 Best_affinity_MHCI_score_WT 6296.8 jETwpX0R9iEiQz2SMpHkPQ==\n", "15 Best_affinity_MHCI_epitope_WT VIDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "16 Best_affinity_MHCI_allele_WT HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "17 Best_rank_MHCI_score_WT 1.8897 jETwpX0R9iEiQz2SMpHkPQ==\n", "18 Best_rank_MHCI_score_epitope_WT VIDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "19 Best_rank_MHCI_score_allele_WT HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "20 Best_rank_MHCI_9mer_score_WT 1.8897 jETwpX0R9iEiQz2SMpHkPQ==\n", "21 Best_rank_MHCI_9mer_epitope_WT VIDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "22 Best_rank_MHCI_9mer_allele_WT HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "23 Best_affinity_MHCI_9mer_score_WT 6296.8 jETwpX0R9iEiQz2SMpHkPQ==\n", "24 Best_affinity_MHCI_9mer_allele_WT HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "25 Best_affinity_MHCI_9mer_epitope_WT VIDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "26 Generator_rate 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "28 Best_affinity_MHCI_9mer_position_mutation 2 jETwpX0R9iEiQz2SMpHkPQ==\n", "29 Best_rank_MHCII_score 65 jETwpX0R9iEiQz2SMpHkPQ==\n", "30 Best_rank_MHCII_score_epitope SQDILVTDQTRLEAT jETwpX0R9iEiQz2SMpHkPQ==\n", "31 Best_rank_MHCII_score_allele DRB1_0101 jETwpX0R9iEiQz2SMpHkPQ==\n", "32 Best_affinity_MHCII_score 647.81 jETwpX0R9iEiQz2SMpHkPQ==\n", "33 Best_affinity_MHCII_epitope SQDILVTDQTRLEAT jETwpX0R9iEiQz2SMpHkPQ==\n", "34 Best_affinity_MHCII_allele DRB1_0101 jETwpX0R9iEiQz2SMpHkPQ==\n", "35 Best_rank_MHCII_score_WT 46 jETwpX0R9iEiQz2SMpHkPQ==\n", "36 Best_rank_MHCII_score_epitope_WT SQDILVIDQTRLEAT jETwpX0R9iEiQz2SMpHkPQ==\n", "37 Best_rank_MHCII_score_allele_WT DRB1_0101 jETwpX0R9iEiQz2SMpHkPQ==\n", "38 Best_affinity_MHCII_score_WT 269.19 jETwpX0R9iEiQz2SMpHkPQ==\n", "39 Best_affinity_MHCII_epitope_WT SQDILVIDQTRLEAT jETwpX0R9iEiQz2SMpHkPQ==\n", "40 Best_affinity_MHCII_allele_WT DRB1_0101 jETwpX0R9iEiQz2SMpHkPQ==\n", "42 Amplitude_MHCI_affinity_9mer 2.4915 jETwpX0R9iEiQz2SMpHkPQ==\n", "43 Amplitude_MHCI_affinity 2.4915 jETwpX0R9iEiQz2SMpHkPQ==\n", "44 Pathogensimiliarity_MHCI_affinity_9mer 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "47 CDN_MHCI 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "48 ADN_MHCI 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "49 CDN_MHCII 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "50 ADN_MHCII 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "52 Improved_Binder_MHCI 1 jETwpX0R9iEiQz2SMpHkPQ==\n", "54 Number_of_mismatches_MCHI 1 jETwpX0R9iEiQz2SMpHkPQ==\n", "55 Priority_score 0.09596 jETwpX0R9iEiQz2SMpHkPQ==\n", "62 MixMHC2pred_best_peptide DEVLGEPSQDILVT jETwpX0R9iEiQz2SMpHkPQ==\n", "63 MixMHC2pred_best_rank 2.818 jETwpX0R9iEiQz2SMpHkPQ==\n", "64 MixMHC2pred_best_allele DRB1_01_01 jETwpX0R9iEiQz2SMpHkPQ==\n", "66 vaxrank_binding_score 0.0322 jETwpX0R9iEiQz2SMpHkPQ==\n", "67 vaxrank_total_score 0.01434 jETwpX0R9iEiQz2SMpHkPQ==" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "annotations_ts" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" } }, "nbformat": 4, "nbformat_minor": 4 } html/developer_guide.html0000664000175000017500000002625013743770170015774 0ustar priesgopriesgo Developer guide — Neofox 0.4.0.dev1 documentation

Developer guide

Build the package

To build the package just run:

python setup.py bdist_wheel

This will create an installable wheel file under dist/neofox-x.y.z.whl.

Install the package

Install the wheel file as follows:

pip install dist/neofox-x.y.z.whl

Run integration tests

To run the integration tests make sure you have a file .env that contains the environment variables described in the configuration section.

Run the integration tests as follows:

python -m unittest discover neofox.tests.integration_tests

The integration tests run over some real datasets and they take some time to run.

The integration test that runs the whole program over a relevant dataset can be run as follows:

python -m unittest neofox.tests.integration_tests.test_neofox

Regression tests

This last test (ie: test_neofox) writes its output to a file named neofox/tests/resources/output_yyyymmddHHMMSS.txt. If there is an existing file named neofox/tests/resources/output_previous.txt then it loads both files in memory and compares them. It outputs whether there are some lost or gained columns and for the common columns it evaluates if the values are the same. If they are the same the file output_previous.txt is overwritten by the new file, otherwise it outputs the details of the differing columns.

Run unit tests

The unit tests do not have any dependency and they finish in seconds.

Run the unit tests as follows:

python -m unittest discover neofox.tests.unit_tests

Logging

Logs are written to the standard error and to the output folder by default. Optionally they can be written to a file by setting the environment variable NEOFOX_LOGFILE pointing to the desired file.

html/genindex.html0000664000175000017500000007303713743770170014440 0ustar priesgopriesgo Index — Neofox 0.4.0.dev1 documentation
  • »
  • Index

Index

A | B | C | D | F | G | H | I | L | M | N | O | P | R | S | T | V | W | Z

A

B

C

D

F

G

H

I

L

M

N

O

P

R

S

T

V

W

Z

html/_images/0000775000175000017500000000000013743770171013344 5ustar priesgopriesgohtml/_images/neofox_model.png0000664000175000017500000014134113743640326016532 0ustar priesgopriesgoPNG  IHDRw JtEXtmxfile%3Cmxfile%20host%3D%22app.diagrams.net%22%20modified%3D%222020-09-23T08%3A52%3A44.419Z%22%20agent%3D%225.0%20(X11)%22%20version%3D%2213.6.9%22%20etag%3D%22rCn5Di2NoBfEBvSAuYJn%22%20type%3D%22device%22%3E%3Cdiagram%20id%3D%22ANq5y5JQ_e19iUrxrAfi%22%3E7Vpbc5s4FP41ftwOFwP2Y5pLd2fSTGbzsO0TI4MwagRihZzY%2FfV7AAEC4QTHuE2yafpgHV1AOt%2F5dM43zOzzZPuFoyz%2BykJMZ5YRbmf2xcyyzLllzYr%2FRriTFmfpVZY1J6G0tYY78hNLoyGtGxLivDNQMEYFybrGgKUpDkTHhjhnj91hEaPdp2ZojTXDXYCobv2HhCKWVtMw2o4%2FMVnH8tELR3YkqB4sDXmMQvaomOzLmX3OGRPVr2R7jmlxevW5VPOu9vQ2L8ZxKsZMkJ7Ixa7eGw5hq7LJuIjZmqWIXrbWz5xt0hAXCxjQasdcM5aB0QTjDyzETvoNbQQDUywSKnvxlohvyu%2FvxVKfHNm62MqVy8aubqSC776pDWVW0Wynla16XsRScYUSQgvDOdtwgjls%2BAY%2FlkPDswIO0JWyFFeWK0KpnByiPC43WrxpLji7b%2FxtFWvDyHNGGS9Pzo6c4q8ZqfS45T%2FoWXMUEnhBpW9V%2FkFf5Yni%2BDu%2BzOGdA2myJdYRX%2BMa1XPd5WYDJAhBzBIMBwJDOKZIkIfu8kiGwroZ16IFfkjADINHvs4Dohu56A1mKBVkjVMNV%2FkjSSgqDzmICQ2v0Y5tihfOBQru69bnmHHyE3yGaHPsiAsJJdvojLgrZkpXtaA0pdflHDgg2ZbvYgz6kuMcxt%2FWp2g0pmuUi%2FpV6mDtYKNoIErWKfwOYDbg6xnYDaDAw8jFho6pEOFFFAxiKljgVdTg5gFzgbezfSywBxINJUs6qgnZle3Hlt2smtxihdhM2zgeRnMNRsDugKKoPDMX9ro9g31mAF4w%2B4OdAS0YiIidj3NBgGYJS5VuniIfbzPwaK53PCBOALU%2BohRT7Ecc%2F7vBabBThoXjhmmgr3FBcSQ0J0rKUT0uTXmGApKur8tZF%2FMeoAu4Fu4mcCGdyQeIgnorxKJVA3POBBJKGxBRY3kUauxh1EiU2GNBYkwAEkcDyRcMZ%2FXBMm%2BHZeweyzRtBUAN86gAWk6AH1fDD8pznKyoGr9wb2E%2F3yUrRhWr4CjNA06yLve8r1B3Dg31QU%2B5E3jK0zz1dSMkoX9E%2B5uNdmcshkxrAhAtNBBlLCe9rOARIOOLXYZ9ONWUQSCGSm9SoA6H%2FjbpZBpFfPsRoO4ewtbneN1LKIqNPNH%2F3njDm4Q3pmD4pXa0v7CUbcvX70rPYaWsdVQtq9OPUt1e%2Fj1U3j5VjR5e286er19lpq%2FWr%2B5oXpm8fK3VpF%2BMmJN4%2FyU4fAFiyouzP6Q0vjJYLX4jrEzt7tFxpglPHalJgcuA6nQ4DowncdAislXTGvQ8BcjXIH%2FZox2t3EHOwBVU20bjQT7hlhF4cJP2OFY37Zn3s5lqQ3KWqsz2F%2FJ61ZLXW6g6Bm2hEp7Ntsch1tIQe1uJLR8Z90EZ99ILDc8byLgdvAjnQ6GxsFa2QnPHqXi200HMH86AQGOeKuM2dTV4UKkjuV%2BIbugBEVrmnUrGHQf%2BX1Jfy%2Fv2oY73lkxXgXiQ4DbkzymyaVNXZVtx%2FyxNWVWS5x8McRBDRFG4LOO9f3lGkRUM1uShu3KdiRjCdbt3iuk6OqIWJ2MIXcNNG0gNy%2FqoAhobtPlwFj05X5AEA5CSTK3IcXXl5n4MrnzP7DE%2FmD2GfD0Je%2Bhya8sZH5Txhihj0aMM29Yp42SSjqlrwSlK1JSh6nnHMe0eGtMn0%2BXNhXa4r1ku6WgZCUp3A2LGQaX1tOXuKCVl9nxNXF%2BqnaLYGx3l06sfSy1kwY1nZvMsyBljkulQ0qWnI1SQVypaHVDLdUh3oYf5CSUMz%2BvWkY7zQgmj%2Bext30J7JAx9IWPwOOplWBTl%2BFgRpM5wR8p2Daf8L1H6m4DYd%2FyLgdhfaDotzdLV34L%2Fbp7lP%2FDCNVph2oWUlj32046EhGF10%2FYyj6zYTLk95%2FPMuXgOjHuzEfkNrVx51sSJihLl09UhMjM%2B2YbrTQIJ03CPj31otl%2FYVsPbD5Xty%2F8A%3C%2Fdiagram%3E%3C%2Fmxfile%3E~ \" IDATxwx^C/Eу AQ] T,@""H$T A )9G$!~?\총wgy_)W7M^4)%!) )*|v I\۳I)%$EvŧIIkH@Xw2~vq=fR ;ۋ;QTפ6ǎz+g%o2$vb [g}M{˝7mݞe61u?%L8:aY8N\Gk}[Ekl^<+˻V]am {mEeP>{ƾ6 h HJI`Ok[?`o},jgi9>%Yw;ڽm7( ]w {Q7|m8b(*`HaCR7KNIѯ>laqo{;^툷ʼF%$ؐ"}L Fݸ؆C/SaTLIB YUum[s^ /;f{.u&.8>E6Zkw,_g*>} ~U\nf7Og'gj /;'WM_lD?}+Z_ CݭD@򅻙G+PaTa=b AYhlY%vEVb+m]sc +Fּ7&׹k[:̰-Fg'^J,nְ)=`T=9!;ӭjm\zՅǵ-"}=f |nƶaETgXUR>hpL["kѮsYv~㳭UfXhߞnlmyr<[{`nVǵُ[6t+VMJi>Yd,JŊXۮ5؊X[wc?[^oê/D;.h5c0"o{|2 *V)8kpQ};qϰ%MONA샙&&rOq&uZͻM#ֶ6j _ުU˃[[kҺQĿׂ\ӷ=E@dݴmC,<*{PBVt +^.\69l~ֿ#Q R Vr9+]:F,~rzX6<;'gxkW_`)ȅO$[$}nyTjڶ!;D/M}3^? z j*ٔWGؔF-_oU]՚p-|wjvRzޛlUCB//mg]pvn7|c&)h]Z?[]4{Z7^M}3p)o&gPa}CX*2]>s3&Ɇ/עVԓ[DdϦ$_m<Ú5o4oƧmiԂ&)huZ]4nGeH@d䭃mپTuBr.q$+YLdKN&>W%{&[w,]|fe=6&-7Ֆl ?` ?` wXͺӋwx)Z<^5ɞZg&gM1IAmssk yw=ΪשbϭMFE#u0 w%&QaT!wZ*\Vj9|Rky6!VFEsFo UYJгmɾI6p>O'ɺ>޿}qvʙdVn5KHÿ,yC&)hm;_e[^4oƛ#nŊKXKNw\jց;D/M9N&n}p [{Ru5a;D/܍2~[YpG#):zns"m~~4q! |]C(:zvÄ;D/܍f~HQ Mw,_M` EQ'Pc6% R$Wz7Pu5^6pH{=JNI0rP{|5tU>>|WR7&$$Ru"+w'8@qR "R 8q9q9#D'@q 8)]" 旔RI*Gͻ_Ҥ’F H p *I2YVR4'ݼ3$]0} $5̅}9B@4]zC%Ʌ}p qRM~I)i Iz\rI/BYLR޺%}$鈤v歐OݛIז:+$+iU@Δ"i>U'$(wbIKz-p t݅#7]7IoI*M/wao]kmJ w%}"oI$ ^{gYB@e3 W𕲚 w%X~׾pw7}\iZ/rW}>tK;D\6IsոE^Rչ%駀i"}/9m\C@e3 :`Y+w/T3]sgT"m\C@e35:VۛvƣrWФᮇ\',RZN+&]3oW%5d[ q!NJJ'ZWo^\ϖ% lz,[%yI $U{[wzIK-#i\/KD$ʠ--$-+I/[Mwy;l;2I)sG8NJ8@qR "R 8qa.tؤNTK:I]u[.ڈ|p *:J*]8v.jqf 8@ą8)&i./irM OHQ$o%&i\'i\nJGl Ʒ;"7F$M+7utCnzNu}H w]$,iQ@nGE>@@e3UTH.&L[VN$>` Bms䮆v:rWxӅ$]+wo)+wG TJR @  &H{]XQIʼnv{wl]fᮄ='IM\p՛>K?sWLft!I*6Us;D\Үr}콾Ir=L[E. MJ:Iْv8O҇rW{L/m+Pۍ hg{Nyoqr¬to#גy=@N_G,(w8NJ8@qR ".NJfRy&iF@qR ".OJubaNOI-7\cIzL?]F.b'%N(mȀD.I0쬋E@B"!$".I~4Yn|%MMI_I/u31|KzYn< ᆻޛ)7\t˳ w$=.7܋^en9Is%͗{޼^{nD".K$I.f Xzӽ%m^ XRt(ᆻ&^􎤺˳ w/M/h&>/7>g.I{]E.d"qaoI{]\.̕}doIǼWK\0&*J/ir8)=U [6dKKLR 8qxRZF2srMwK?%ቯVQxrfg]".OJ2 a7?'q)d&;"q;?N I?J,7ג&ʍ)$u X:KHgZ,/eqKz6&$\,. X*'iKOp>Iȍ(C@ąqR:B~I$U/AHj&ۀu}ᮯ7[vuqI=&IPr+A?XUoI+κE$[R o (`w0̀$..yӾpw7}\БN0&$5U RjIkǒn溅>I5h/ (".pLI7LU1gΒmu᮰;&꤬]I?KZPonuϕWIk$ n@;DKpSm9pW'] I?K>R[XRyo^U/h7 "o wMkMIzOh+!whko׶pͼB^3;V*`r q!NJ;J' Y;@\OgK+Verm%M׫o&! i\/cy]ؾvKZ-4?k!w+גyhrIwyn)I y/CI)sG8NJ8@僓S% ͠Br-Ob'@q 8)rI)sG8NJ8@qR "R 8q9q9#D'@q 8)rI)sG8NJ8@qR "R 8qI+'$Xn PP%G#Ĩ =)n PP%OsW#ĨS,yen PP%_#IH1*yU+E-@A+9%Sz F%6+{ʄ?G|O\4uWkBnbXmCΑn P$ǻyKwrV4I+v(m@ފ) %$XbJ…nPP$F=VNRw&.P<'Lx{njH2 ߰]KFM@~ڵdʄe^OGj%=;`I) {Wu(mĔnS{WK)=.KJIS_MZ&q͝"6 RY.iUµ)de+7tL=r)sj keÓR)*J+&4?[1P`$.Z!ieBߤu)?KQR?'LXWGr$yu¥CV%9%{JLԀ`ot[bVONI螔sbJF>DĄKHHHt['pQpQpQ{w,m@LsQpQpQpQpQ2[&Dƹ(@(@(@(@(@o?-@ @ @ @ @L Qq     [&z(8wwwww-e@`;;;;; 2 0DDD7dQC{l>cS+DrUzN$x66-c ENvԆڝbO y?P Zwnȼwl_l(*j_lЌ+xܢ ]ӡ5Yk;(*F-o$:T{tV۲g{ewט9>6 ٻ{v{uhEQWԽk;>zPw96vۿmKQ1]+wJf?;׾~o5[ zWwM{L%y۶}XҜ]c"m xwvxK7(_~<;O`;{u3;Ʊ[gl S?mc" vgMG;=g ~|(*d;=+x?ֿm?E}[O[3#}@J-ڟ߮5aEQTk{WE3ڬT{|6{S:b=oG4Ӷ76YU=k:]*_(vyl ޞ5D-jݠYoٺUZM;7t²-}.Ɛ =3sm5h[;1kn,REprx<_g*.kwUZM+Z "h^o[Jxx5#kԋ!F ݫ;&Yom*ͽ:&F7.*ݘ{m?F}UV.5MмqޥVLU\XUbvU[mWucDb IDATմ%J .g_>tJX=:|?"R5-xĿŗ4IAۃ>˩/k}}IKvةϱ%J4~CY\A<0h9L+^<=l3kҽ fƱ f߮(q8x#|n=|Q_ִ~CgZm>Ėoe[Oے؄;FӬCѠevikW?9]n7ʿAl6q[/N[Zu˟Ɗ-f-ob˶}g 7jj]Od7vmZfً7}iK~Yo^]ѲqXق#5vRS-|%-eSSW7.bKؘ6hK,S~2ן_-ߚ߸ wﱥ~T z%;;z=1v-u7vV6=mukK`cil˓'2I6c>[[W6s~o6I6Ct6dd_7eMe!gUkqSנy_$ٸE;^+_?uA]F{hQ wb޵Yƛ}ʧg/$[8%V ϰ[D۞5m"[u|n=hQ_ְ'ƾdgn2qmkGR6Ŷh֦Cnd٢-ۣ#XsƚOL%OYg|os^̮U^Ubq*$'v?ěG=fu:n^Fuyv͍] $?xŕ>s2]&[p 6M} *1&zq~=<'K_Iúd_`Gclv[JeU쯯GW5i`6<?:jըrfM+E\7K+p7bn黨JUkccMYs=F[5Q/M ?6tG̷%J͛$oMnڧeg7}g#nqWxw/=Za^47/jҢ]}Cy&`|7y=heWOq%vݏf3k݄;1יʱw4۞EX\ْy3#޾uSloGZB?[UTֶvTPvmvۿSVRوP_߻5=6_`mWŪ5KmoAӬ֩gIuO/y-|em&Ϧ=l6~k#m3I6j[叏[i kټIuYOdϽ=9>$eAy?[n4o&F/lJ+Zn4iۜ׿V;- MiqfGExs+VZ6;$'~=4Ϳެ?ΨiJ3Nn+f>lW\Zʗ+eVGn?>_GY.ʕZrV>_avRx}ӬvJv}ˆ)];kf?Ϳ}-ϻtF/U)]{ZEnz:*YRŭI3lϦNjujwoiwv횠en=𜓭F ֿwl#uX&gٮ!oHNFgX2%zr'E٨Aڕ>g/qWP ~V|i+WnlNԱw̼ wOfo8UJ {xM P+^fo8fSV Ue6y!`~%ֲ}O{հ]tŵ6)=#^ckҲ5Wٰ9[\ϗCfa7ƹخ+ ױ`Z6MC{r~iiإo+vOzUq5n6hz^4+[=N\gEOL|a?*TV;@L򇻝̾u`0d+fzuڟOf_ΰ ZrlG폣l>VDQ{f_ΰJٰn_?lh5O[ag}],7oŊNWڟO?hVl_CsOIگN_?ly|kըh '%-;k+V&d=8& dU*v^_lnn;<ņsկWmj~:UXx/g__L>z$__Lǩ'W~=[گN}Zq6nf/ͼ*W,=دNojd=jz_gK-ӕ'헃.ͬ^v _G6o*Va\⟾& [蟗8my~+UU|]sKM^}Ŀ|v~V\%+_]ٶMxIZ[JլW ޳\p-WɆ~]:` h57EW\4ovƹhVTee'd&n3^=jr,]mtu;*T ǽfZXzzvWgmg4אwbSZoԨ[$ߡv)U,en/_N0bBյYv_mT8v[򤇯Q?O{OKoP?y#&{y\jT͛lWyRv^pNkw*ڒ AUg+fv;_ojD+_mXGou*SѝGq6kL/2K؋SI];vh߱}1nns=ؽy:)s{YeB~wzuqC3zU3[GX:?.]l(Nڧ6x; R%?p &;}>1*Ddw9=kqYy~2ZkDjksAlZ/^?Av}sFVJ+ig֫_LutރݮvmElt jTN;hn&4/&}{THuRy[8Kм\k7:-h/OXB,uov{(QJ,f˕JYŬr2ƚ}Ά}g(/4wxΙ5l\R;o]8s|ƓVX~Ե G&ANp.}m8 #m.vMYRm@?vrӏpW|nm/(a vٹ[YRelָm6j Ĥp蘨(cGzn1ֵ%vC˳;cqclvrבIZ%1;:ƾ|] ܺ~;{Mo^;Oǃݮvm wyul[B~. 7vJA.:v>֩dcΡ7 jT/g|_1J*nkO0;:Ɔ<ƚ67\|'UnO)]Výpqς dg#iUG˂[5 |֟v?|ͼxXTďܮc%_8C{6 jwo1;2**.}:(j?+Y we;VoE/3e?J K>nc'UYt4;2~?N觍ho}̺.wжڵ=7h^gͭϱzm}>|!}2~?~?jT捽~?~;0(;VP![0H9U\&h#kk5wV=ha3Gu2W -o6ZeCneM5m|Ma3UO6fs;ю>{ʔ.nw}ءe[_e }Gؠ>X3}.\6,a_dc?}lvdߧ#767Oa3gHQ<<~;0F D:v]^'g`_zr;1)-=`وo⟷tʝv?N2[Ӫ7 X\Vm`'U5[Nڡ-NvvfK{|&֮9AtY-ZتT*cl_S2|^|uyծQ*U(mzw:\{ľةu*Y2ŭ'{gov>iE 珻ʗ+ijCn]԰7]|ծQ*+e-<qMVjY+ZթYOÿWˬrV6qȍn=W׹n^bqeKXEӫD2}F5p>e=QCVru~ւ^~pW|/(*IfRQPp=peoE{7.c3޷KPPxp &^fX d}]fhiqeKؚٝ".:V/]^߷?(*O'Mp^ORv,.9*YNUF<NQkulGO]^56O1o|{LQQU}"})-%OQkulG.Dj#W"~EQVǶw'ޣS{XCQkul{7]^Xw6ߛ(*ض wyW sbh6aǶu(ʵ:ۻp'8y2 V[׾޵ڳQEv]}a]nXr{uWwL(ʽ갑+wyW sb;N6~_P'K$ݖVJ2IeyK0]XҳHzAIѾK *I2YVR4'ݼ3$]0} $5̅}"U|+uKo1/ ,;/yߗ<䵛 S.Ik%%(8^8Iu;KHI-Z[!7%-uVHzWҪ))E<}~OHQŒZ/1p Vq 8ypwHM?pM[xӋ%=]{طkIѕJ w"I]KD 9I*aINAwb'_ /y(nTp,%} —ONՒ~z[M@wbU|s!$wNhtL|)J~_l9,K!qZs=KOpE^$ws&!ĪzJ PG{"%$wb;1R0d3 :`Y+w(PEϼw垥 TJRLB"U+peK/ߗ!ᮡձt?{$.w_]ABrHi!/;ᮘ3wͼB^ mwbU/_Ge%-guleN XvܭuV/`I%ͿFҗrC):[[!YXXL6>8oy9;u=}g&.M2Nrc }-g-%iz}rcϟ(!>;)] qU>g׺zz\.b8r?KZ K޺˼uK]Toyr?l=Q%}%i~xm˛1`ۑ~7@ kl$;o-;SҿzɅ)߲$Uo[ik>nQph7kOFWCvBr)WڕR>SZ r)Pv7}/|eܳʝGt͎|w DC w_tzܕr[[x\7}eIoH `֒> +|BmJ[PZ).w5* sߙ Tzm@Y:LKiw(4܅꘮u]Xf $^ϖ B^޲$lΒoݦXjOSJOpwXݙ)rte@S%sߙ ] ̬}YuL~]]upc0]Xp,Frr'+w]K.\ woJz$`YFW X^Ti}Fke1.Tt;]XpW_.xT+ubR[3w]==?X w %+Po^` zPy}3wҽ}~O%:&ٛX_˪cE wg]nmIt;]O^#5hA<JuD_W-"GwbUurT.]s\i/ȅV:N9^Vpo޳Xlu6Hwz|۶:oim\ȝLڹRϷ]Nriξ3UwLw\rXYwLYΒ7vVH1]_*RFCy|ܿʭD3/3L@܏w̅}#Ī(=*$w[LG%@- w^#}(wbU|]gݪ o/C~raeer+x˫)mnq'>[WujD33NM#sZx۵ kgf)e=9@7}E.3j@oAw{C3)ߗ! P*7{},X0ft.0He5XgIpΕC du@D&;/yߗ<f0Fn G *e5X/ܝM_ X'B dѬ]8!XK 3 n$v2Ү |˜%駀9pUY ו?LV."Ī||' |'p宭Ү͔Rg3]Dx5} w@yp V/Pߗ/p_cr K+8}%wzIxQVu w=䮪IC^`( 5hVoDC=sTwbU'_S fyVv6D.x˟Xlܘi_x{J;Ȩv:N{HёIzBPU IDAT2w {wy(p7NOV(8GKZ(w[! 9HqjD%pzKzb\DxJY *e>jNMߖ(-3*MwbU'_]^"||5J|\8Uiao/%.zrcߕDC7pN; fĪ0Nٗ%!wOk}+~>/K{Yi=eKr>esP]@.#!9X,yӍ%}$ewgB/2] sݒ::ݔFQ(|ǽRVݛeMݛ_YY.}PM vrB?c<ĕ spxKHHH_mj'_Ʌ&s{2{&.}gm-sb}/! Hڕ Dg}g~'_Y krv6HIXR;;oZy\@{Lsܛt|gm-8s&@P}w'ƀe.ew ?G Vq `K/h<;/yߗ<k}ɍlΠnuZ=p^.wLp O|{ܽn 1K-wKFVΔ}ε "d$Ws_K"wKI$]r,.gK |!jP";/yߗ<䵸\jMRӁ.AAWH**\eMn1\H|G=[r!g\0̌sM#阷Mc@s;C+,9Do^[$2Wȵ=P U|+'WˍcS(`ޅCW8^늒KZ-ts& 'JՒ~QXW$G\tۅ^C> Nn2W`5IՀ@+_5D~_P.>bЕAA{)rAeArg+|zKiaF[ 4Q ff(>wQfJ'w}Gϐپ]FW/*FwbU>>J?n]nсJ>})B6jx5n ]40>`Yկrϰ`yr]*%gIo9rWf wue1 I?2z]WwDW,; ߗ/k1`ƛc?sAAz=UQ.hz]ϭr>g3oWnl:_}ᮄmgz]F ljgwD8"Yޟ;uBuwUm%!i ygKz^X?{%wܠ$!i?4Gvqrmr:z/t\hs6_;P+ZZG;>?Q@VT-_xZ*VEdXě+ VEKDlh6PQfQClG~~|f&$ٝ<3;3;l潟pׄҸxuG-wqo*%'=LR2I{NxVvtȎ}%=+@~ξ)ZK%OEd*xE!Ltl?vE'fyr}lz91.s'퇘y$}g;6GM5,@Ҹ}kWAFˆ.>RTW&J* W.ɲ;2Z6@*g^HЇ6tͳ_謻P6dJڹʸc_Ld ]ř>[}@Ҹ@B/+/ ^;BI۩hk-$"s=?~tt d;{G +Ul?d `j);Rh7^cWұo{g@ 5x=J_e?HKdCA򉊝*)UW. s$ qn->kɞ㷯p.[S]ҽκc>@maّ]L\e[(}/V7PvD>L5wM(/^/p}\QrҒjEKoXcTŇ),߮ᮾr5X %Ek׺{khJZJCZ,]kwZ&+P7>_'Ɇ&wQjpjOek.w}K&/*6o_RSvPk %w+;IIۉܹ[ɏsGC"5!.^(>4.6[vtm|+cI^DzM+Tslm>#D. eOM>ܹnQulelxhwpκ_ ;bI+jvsG{kTv6o2pׄxmL.T|iB\u@ @S xu'l/%$Ce.lul3)sۤӴm dL{7|0ȶ믔m9?ΛRDŲ׹ϝols oX&纷~{'M5+ @J<<)|iBi\YҾmIJWֲA(۶[~¹B6tMq*N\vp+isWen}- ~}Ce>Yv'R=gHSȎ)IGNoJymJ3h]Ew_ /M(p7-Պ#۝er) I$ũ4ܳ|DkBM*ڏlJʆ@w5jGeo/g'jg0svswBv0#dC͞mgɆƚ\p#;*P;[R\l;Ͳaȶ ȶfy_v4W hvwdK^nw`.zfJPRu>Se[[Wl @kB).^NyRel ~H%[v\Si!;bI3e>ݹYI c}o9nAEGN:O9[<EHgYp _5.ղnZʶZw}RΒ h{N*:$眪dOv9n?g]wM(.^E}@4bsY s[(%IwlX/q]U4`J6ܝY#[# `;P\drÝZ6urOmm#謮a|9'4W|׈{duU)v̀cN`;P3_6D6Io@!W tl@pw瘒훷[s7Vۍpׄx|SS#d% y'}GiÝg `ŎziCe'S,pX6$U t;rJIo6b`kǩkdBf/V@gu h&Iκ$U;Ǚ&sjjvuvd\~.iα>p/m-n&P0ۣhjO>E:نrKRϗ&kZr%ܭRls|ŗ$$|iB).^$;˟e|R NL:TņSdQrW;~]|'d纩xe46.ۮ>IMI~&jKgsWtRv)u@v cO5 _!wrU9ޮĿTqS%mu펔F ;,&.5NJ۸}ݳJzYwp SEl|WM$sr /M(ѲJEюūeCBk!HeEJ6u-A*gk+ nwjw]פsǕn^α\%]YN{"~ ^vV\>wtOMv;9J*$n>T{Y:!~򳲯G'١:ۨGN%W\|h*|44ݴW+FZIRgIJ* I$ũtfggy ]RMjѳ|l`rZHE6 ='ۡݲeen ]!ig+ek-SIm<Ζov&_]IUl?d=,#;iw}Ttĵyeo W\|mӘ]@V 'XH:ڹ셻klT^.^dsC.qNj:@6 w$h@!\TـNllIw]Z$ wdGc& w;,ڥڿ$}u<%~R@+m[@ 5Q۠yb^Tz&6Vޕx鄻Njp7ECە~KvPϞwS=xuN w,%lE5]sskEoﱞ}/ek+.Fϗ&Dn}:^x5Kut]}'5w&jMVف\Z~;D5tnl9zքNKvmeÛ$Xߗ{LL!ڻFɾRp;Ƴ\.۔Od-j4;*W]IuvG=;D E͓d,_!8yklKd-;T/QɬV<kqd였P׀wey/'&-=sx7CoPK?ĭKvgeCEdDuNjzlO<?Qk]sZ-6#ismI^MvRq| ?>*~elEk]Uݿd!>skeQV'٠lxBl Tsdkh݀˾Key,nߧeׅqϦ5^wU_k4ɶ@r|bOPuǗoɓ JDvm9Ϋ{Jv(:\o{ϳ_JvLwMWlli:sE5>4ݴu,ي+I:S_ kRz.y,[+gA~qzҗl#d\$eOvHXɎ  qpwEJf^ wlP msjlSK)p<ꃝlPd(JvT38W]TZ>ޞ~aLXɺGkB|zr|9ϡц}n&zT~ x p _50%l\ 7g`]/*Zs':%ڼѧ Jl+;(׊vK]Al?ZKih IOpwi&+P7>dr=h> ls~>wlz_!_>vqO Js3؎Mݾ=eÞ=9pׄydCt ViG6*j`)'ֵG}Mlen;*WCX6T͔U{;Tvٲ幯"/i΋y< /%gs*T]_PƔ nG% +.4>_P'):ņe 5)hlﰾ\-uq;IzIő{2ornN*QIcR=odGzMvMϹ^mfrvfls퐝,%\k';32Q&* _Xbgfg#%QddG1G?gxk)vnmj&9Ilkj& w_5y 5|iB).^w@|DޚղA݉6Om) 2Z6vBOV6XَpsRŎxl69Jn/E;PKDپd.6uw"D)8Vp' w3ePѦ,ZA~򳲯ǹo{H*v"WP`x$0P`t }P`2<֨gU;5fg9\eg.IqJdGY^ydk!mlYI60 w-$"T-ۑڕ,%\&RW]hS/6~`,#ikܾ=<([J6p/t@.u>% Lf](?֨}T{b>wɆ}RݵDd*tut.dB 9'ʆDJpJ7 #d+YK6j}MpWh("Y;y=~ ۻu< &gئ^wUuy  LYKJ8g}}f3ͳ{]'8Glղpl#ism<¸s@]J£:;P`WѮ -ա@H(`CF * \a#[?+ErR4lT@މz s.^ աj߮>TTZMQi%=2.u~Γm(JlJ:;.9*! Ȓo* Nr~[.J0p|ea %f<͓6;^9*~BvFH, mk* /E &;Q[&P[܂6P5@c@[  IDATTwJ:LAw M4/KDBOi69M>m#`=2}N9-X^NapTᮒ{ޙuHHK w>C*9apK*E%~u'U|ꆼHy`Yu׹s]]!Hy`YgF(I$tvxaST{EeU'9 };0~@3 L\y *" %J(0lSĥڂj:L#oW _w q6/T ,%YˌfJ5/3zg\(/ա6'ݸaYALf^,ĝOq;}mT>ӟIp _usQk%uWycpュNyBSXXXsQTVuRQIӚW^,:wtFGCU7KK%/)_?=sɋRR4\, X8z~H ' .,ܯ$<<ӵ0X qs%KQIxxQY_Qi%KF@LHUU>t 8hp3$@L7;Hpp  $@~Cwow  !@;7;Hpp  $@~Cwow  !@;7;Hpp  $@~Cwow  !@;7;Hpp  $@~Cwow  !@;7;Hpp  $@~Cwow nB=ׅ zF n\WE$,dSN~ϢU\u]E`TuyPP( )o\3 NSuy UEfʛ̖77[.P,Wd6TŇUFQS;7  +ma~Ҙo^PU~k y吘<sso?m/Q(Rpy<"ʞK+{K7£(^{KM;5vWh~˜*)F-?}^a6T $?£JoKÆBi` £["4/J. &d4ߐpQS֘f5g-@Y֌V+* O%| w*6v|YA4ivn&p.* or/,ZŬy)z3Vo1\ xMGgᮺBirk™@wiHY[cw̪ߚ~PZc}ʘ)f)?}T@w٩4<-X6y٬|wyeJn3ÜL U:- |6eߙCYϣ9ʆp_πpW9s?3G4iyng5}6/h̖Y[.:d>X]s8#UcCw9 ke; e`I8X6wN{լ|[ Yʝ^$\H%;o3f̬,_iӦqԁ2v;3oWݗcRp_;SΊ"(f)OUVeoRp7ҘOfe\r9Lr0WfAc~nٮ³6z|:#̛\dzt9.#7Ts'*4Ү9~f`}.HU62fߙhz]pm]L;>lykBqc֬?3ke# w~A>no~c*7,e4nc19+˙nvzDLu]5xnaV6?}栮{٦U;|y͕o;{/jڶ,=fAefs5'/ޙ`$Ko7o||O9FO6 ew&O>┚91G#o=hZCLȶu_K,|Z4lFNZe/ YIl+ H&pc>y,ʧo5Z4ﭸ˘O3q5Xpd6f]ާ{XܪUK3mB'kY zk<ۛO3|xMϚH2oxG{oMY~QGMcqWCڳTkmeZe.'^1KgޖK4١͎f67z('^! wbκ2^#Y<*sϻ,xFլe]ܪUKS9ƚ n,fȋcwuz^Jm0{O ݗ0{ώMmm@lny|lZsVv /wLeu|7yYOi٪Af“Ufm֭w0z;vJL-@2Ĭ+'saVcL;]h$+DbFR>7^\vQ5˭Z4ṃkLgÝ1#/9Fϯ%flوZӇ́fXXc>h9.1%;<>ZsV6p↻y~Գ.3t ofy씥_`vjtڭꆑ5_3GS{燙= =-昩t:F n2Ҭ*_d)2z[M9AgqY1?~7^ksyYnP9._q19we5޻ f:Vl$ Y׿N@+M@}9t^l+[_p↻g"ft{S:di׾X˟1{ss4vbʞ\a Qjڵhy/m{u1˪rsLC~❿3]lG̊lcSeuYnժ ?=fyך:\\5wickS776sC+a5ñm#5[a b6|13?nmLñfי_ut}1ic3߯;s{]ڵ1Gw,q]}ދ͞{bZniYG3ϽkVG{̀ߟ`6fYGN8ƲY'*A)3"W@ ]vqݘ93gyYڵd>3g嗦eVeV'9+4ܐCuvkq䱿6]wK򔊍F7ce2f?m{%h{(f-[_ p]p7j3kyY?`3k יV\|9f/Eb?,O*`$V}|,& wElBiֲ"_]mfT}圂fYwI[AG03>7GF>fCކ5x;Ҭe뚁; e7;3rk^1Ob츓yI涇B=ݎ3S+G7v7g`)d^kv9׀c_]{KϿo$1;_p7#)f-[ .'1_,o-% eZﰣަט1_<zfvL2<Ï9\t5[o$;JX~p7a8ҬeB_yl Y]3& wP Yw~A.n+sŧJ;zcB4kٺz_FMH4kٺ:_n Yw!ݺTl]u-ҬeSeop ↻ۦ͔,;Ҭ嶩#| w.5d]EH(`(LuO3w4FNJSw![sW]^PU](PTQs↻['iҬoB>H(`ř>@w w3C Y wp4K$\, \eMzBirӃLp C]v)*  i4l(̔>-* $CGwŭ %b K5wp4K$\,_C]v_C]v_C]v_S0`@Qï{c+ w $"݀<]#+Iג4O'V]$='iKj`g%mn*SIzfIZ$_tBC'p#Ӌ롒6K}$-CsƧ?y(]PWXX8m]s7Z兒9[HERHZqN,":vIFƮ*6=&w>B.>N|gp\B߈ uo>U;UY#is7ek$zr}WJسl$.H Kz> Gwׄ<㩹u߿Z ͔kHzsjXsk{k-i~k+2vӸ~T.m1M_$b} I#%- v^ݾGRD-16Kؓex<#isN}pw/%.$g$td̈́p/wZk殰͸F#*;8JK/aNfHoiK;!eV]Ke;YK)*%ye)cI1#vvF s еpZ\țFw%'26-;I6E;5R4.[/i~WSVl ԰pTNٚDd d4 G<8璏p.qq}䣳eG&ilzJv'eIKgLnp|V6͗sZo$)| kdG$;rGwمkd?N)j:NwYn#^tgۉ,mb^Y+iX p#u=UԉyBd4e>#vŲ#bKѩ~ w+$ l{TC;!e.kٞpW/ ;.޹lwI';MVN4Gv6 ׵?Ni$}.\I=(v^ە<}% w% {i>Gw%$T%I+ws*d;Eϗmk/IN$>TJI[aސNGKZ$rlc$'# %Oe>vD[c$mY%1&6yF:yynt]"Se>$;uJ *-$5Z@󆻾,=ekw>B.).w Is?@'IJHkl{֒KQR{羆t^";d'?w;o+i?I!}>meQ%CI8W:,o6')isa9? 1Ͼz"@vJ3ܝ iaL^<%۔r여CoK~te5_藪eϖG]vIqq}+$[冻ek\{~(,tJ:¹ݐNe?[J6,I:ع톻dÝ>Iɒxϕ/9IE]= ;5wpىpL".qq}ha&(vT%-9(Iwʆe4c͔\ܸG:.[s~des@DC&|p]ҸPtZC$]&RB.\\#x@v"!w>B.9xq+ฃ%E+iH/dbؼ IDAT|@N !w>B.i\\/ ~q}XI#e/mճ^<ʎDYCU͊pىpL".`T22pىpL".*;-;(;$& 8Evknq/rU9Gˆ.9}_sVp\*6͔4^V|htutI>ڼJ:¹=y⎹B6|:H:ȹ}D\`&5<ܵ?ņ"oݙ o'<-4ȳ=ᮍl͟c&{!@v"!w>B..[lp-mW>[dcJn+I G kJN,s᮫l@:ǽV6lW 8Gm$ܮO܍U[swh^;6cMtܚ[{%R.uSsh' L".qqKʆɆ/~ ˆRIc_CF;"/=n';P棒4Jɛ*?I8;J;8{B2E wJ:\҅M9n|\pH<&Rx:S]G ]vI C~+NR}IZl7Cv$Wdk&;g/ں,Q[eG||JCAld_ilGһ8>m9ъkᜯۄ%q9ξǽ޹1g9^l7mzxKd>+Ȏl=9ῒdGݜXsGϷ ;[\sA&.u|;dXzIH(;-¦pgSOHy|nݺ.-4O$ʩ=4MQIe_*Wf\u{ DzI *#K.;z e`Y0gP:LK*>@r* N./ yPs& ~%Gj8|~2}n']xaSTW>侢|pxL /\g$^y *"JL ;HyƸ?#]-rL, Ov.W wW _woe|)|qHEP`Iu(->Q(镂D*71*Ӏq/w T~NЧ8Li4>@*|L`T_vº^F{3^KDɾ \]}uE3#/?ZB^W\t`IxtF\`ixӿ{_>GnEeU'? yesO\Mi; .XR9ݾOkJ* GcHYS`IxIr[:Tn+* WK7^1i4"M:ul']T>ڽ˦bC4JXns4,ɭ{kfoM?P(ZV1yMM M4|pJӂa3쑗wW6|O4IY63̩+* O{ D>]ϭ̬ZҤ՟w'X.͝^5+BirWm+ go @>tvKϼ(㯉ʸ߱S"doD.n+<׾+g\p9 ̞?;<צhd9If~mZje}tQ>#=iwܵf2bJy?5fǶf}G9cBo9+c9#k;j=KכS{ywy=]nf+ 3R;f2];$㿃)1b&_Jk]9+nvs3f_Lm$3fLV~fcgwY13L<fOkte˖ff-f'MVͣ ި晗?3^1Мx5xbu-0u9>GdNyl}sdSQǟ^sF;3&k2|>Fp=ΈqOZ疧W~n_Ҿ6zf̺ {O(9zv}b֕dFͺH25V}e(i~{s3hČZ%@tpAj~w wcD̜_< s}_4;ќq5х#̪Yi٪5 y3lZEw}bwtܵiѲC1\pE9 S)gOoN1&>0].1sV~iGÏm8HsMc2{hh3pi8yњ CK*/9Lͫ(MS?QF￿Q!.nSf/|WN= s Y˿0ǟv)syxAdfTn1aZješ}3qט̙][S̺G7S_2ۻ{ (U(9 ңh`h+ U"&ܴ"DP(Z/ȀUAg@){gH&&Iy=~kd\{e?7~pIz:g<+CuYۮp'"5"BM2Hpa۱cz֢EJ>z!;߮vA}]MOOR{衇l.߳gOU!YݖM ao7mXݶt֤v}_3Ӛ|j67߻yt#K{sE *:g^^a]6dTļ ^ ϛ6o4jd?Ӗ†j^-bο~v ;ݳ\NDjF2d avWڵkN;"X-L;ؠAlٲeZpe->}Xǎmԩe֣Gիeeeف"-+͞=Ҭ{6l0;x𠙙ga{ٔ)SL:,%%u]n6quf6~xҥ\2ͪU,##k}>\;v 0ڷooӧOk֬ísvWؾ}9 wwZ͊K>sSz'n7w wEk>/WOmw ;YFls_FOܕE%V\ ;Nou-|v=Kuvͤ{#13Zm<j?lxYњOl٢?^WZ׆K}f%ۅ[j ?+Y],߰>s-☭ϻzԥW˶)܉H\7wװy q::7gm~7~سgOnϞ=6j( lU wֲeK۾}{ 6嬬,+**Xpg733<^I&uY.]СCffvҥK,33>33ۼyu)]fӦMꫯ wvAۻw5oܾ曘uB֬Y3OlСVTTp'էp\pmV:7uw]9vzļC_n-x8<;9vav/ '5Z]cǟľvϣhg6o{?zI]d!#o&MO=ǜv6&MO fC%ӝ Y,_c~֬v[? Fpw.9${[; )[ߍ, wJ[`1֦M̴LKMM;#b]QQ׆ bg}U5E͛7ϲ̅7ݻ3 7}tС}ݶu3f̙3vَ;b! Y= ؍7ިp'էp\pwco/|ISNw?ąZn]EH˜mf[̮暣wӦM Νk7pp{֪Umwe?]r%d3snuڵkg|A:Dyɓrm~n&M:.UᇚD#ђ:A6,/ܽv޽{lGEuYΝ/:-Z^~7[~~~u)̴4;|2WXaf击CY^^^cUV٘1c̬SN̆ fK,iO((%?xt-'44ѭ w"R#!$dO>ZNqƖdYڵRSS-55N8袋,55 wfsֽ{w9r߿8`閞n͛7;Zzzmٲ8`{!CXVV-\0Ǎ7o:u={֭[KII ޷oU222gϞ6eʔphro֯_?ݻ;1]:B!֭]uUU)%?VǿkT(܉HHP :LcRB}Hp\pw{[Vǚ4t{[ w""\2CNN.no޲_Mju;.F(ѿiHZp'"""RW)%?r6s4i闋DDDD,S͙l_,zCZnZr(܉I w%{NhrN9!Ӥ)1ӆsBwADDDDH.-w99\MjyZ;:J.rs us-ߟHp\ts-ߟHp\ts-ߟHp\ts-ߟHp\ts-ߟHp\ts-ߟHp\ts{`x十sj:( w""""u]rIe@@`t:ÀjB w""""u]rI4IPK.\OvVS Xv8۾%0x?pO-`o6oˀ@3oj~^u[U$Hp\*qs]pW~ X}n a敯]paw?}Ei[6Q^ 0x8j?!/rGHp\*xpw ptZ-equ ,?}9#IDNDDDSK. w0Dx4jpxxhͯj ,WXܣs>DDDDD0R͑-wµ5_ 䕫^$.#[ ;3a„6YYYƍY6IzzB.T2ܽEi2J߹kK@ }w&G͋~bspW)܉HM5tJiIVVV"߄ wɥnnpD<x2=y<]\Kho^7/qt93DyW` B\URD( &$:TdÆ f'tq_|a5}3f̰{7.u߄ w]\\wDFNDjJCw|;vحj-ZTعszj33{׭6ᆱU w=-^{pW:$!u]bEcp'p'"2nܸ kXԼz=eeez#*Խ57^"޹[|]}oإiIDATնvZ;ӎ~ osN;[nfVpe->}Xǎmԩe֣Gիeeeف"-+͞=Ҭ{6l0;x𠙙ga{ٔ)SL:,%%u]n6quf6~xҥ\2ͪU,##k}>\;v 0ڷooӧOk֬ísvWؾ}z|;ک4$ w"/QMYYY{0?Xٳpg5j}y;w]mڵwֲeK۾}{ 6嬬,+**Xpg733<^I&uY.]СCffvҥK,33>33ۼyu)]fӦMꫯ wvAۻw5oܾ曘uB֬Y3OlСVTTp'գpXU w"5J?ܹǿH;?XʲsNKKKz.J ؈#kmڴL̴T;")+Y߾}mȐ!vg[qqqxYU]^^^Dڼy,;;\۸q޽"/s~Pt۶mnھ+33k:M6-\;wp fݻw[V"ݵk=v%ؒ%K̅ٳgi׮}1͛g'OnW$oSH +zW/z\ IA);V$D4pK>釻_~. w>kff?.:ܭ[:wlff_~uYhѢo˭KYeÇ=b 3+?:tìZƌcfwr}ff6l0[dI"RgEcW7 wu wC^VVڮÓO>i֩S'kܸF<:Y^*~33ѣQ;3z׹sg޽9otKOO͛[ǎ-==ݶlb޽{ې!C,++.\ƍϷN:YϞ=l֭?۷\*ֳgO2eJ8jϷtׯy睘.VBuͮ*T*"uYZ~vƝ>n`-^6w]! D+`=7^13ܘv[l{"*pq`sY +o^}VyG Očg;k:pܶqR:1O*1`-kwT$DDjΝ$^(*3$oBD-w;Ac}@))%^ z-w>_ B_#8`0[v19.x2:J^ZWE޺Sfz,_^%5+;{:]нW!U;+;!Fʡp'RxN5F_'p׻lD`?qkiS9cL7Mq-^7ʩGoU b~į\s-w'Pr ^PSI (gP;G^u~ZxSpEv'gq~'qp'""""'~~Zs}jDʗQqh|}A;g-q=:,J߹;zzR5Dh]q}~A;?N;wMpx~pwqc/eI\)܉I%o'Z|Sθwu8Po4\ό/܌ ]b7VlXq{l{Om97ɟ8`#7Qw0F\oOB*\4mz;pvwq-mNXZRkL}?~zI\)܉I^5w$ߟHrc7qc5õJEScODDDD$y%u/ܻjS2=7@ G@Xg]UCYǟY}H5$ODDDD~͵$~"""""qRouR?JߟHgpgj}Pn;8QDR n_ix7+n`YAwyq̽䕧xo ߛX`pzÍxȎUm TN^č?w; 7xx p6֙z{uZ < |ߛ__+/1`(܉I%ngBͩw)( wPvK\|?x勁ρ0@]Pq14\[x\t)eptٸ}~ <7C<,;8dM0|.4 wObKix {O| h^y . yV;_KoӼ,JԥAQJpg@ sU݅7y^ eGB5`^0xA޹+䇻f^f`y.k^Oۀxˣp'""""7qwOF; |wp5~ݩW%ݍ{.9pW;8s;؏ K~LZ3q|~.zc=)=.}\-ʅ~ws?[WV+HTps= x^P6zʼx~V!7zl޼{r;ic[r`ϗ-y\ϔqKK1. u+?ߓ5z܁kě[\z1?F];8͵$~"""""qkI$DDDDD⤁\{g/zJI<\K"'""""'\O[w[%w7| \g&X@Qz"̫aDWh)܉I%n| [#L\Ϛ'yяFsf]sUIGNDDDD$N%r,[|l k+I)܉I5`9`)n71ޮy)1;+o~{\sw>7yNXw9p7+޶WWoz!oݍ|/Zzt=( 7v߸v}7_w}QzA-4{ XsJ;8bktٸ E[Pp787 xpoLҫK9 iQn*uxc9nSm [n7B^ n`=8`rK`m*qN p'""""'U wyV;_K\h9+dkwm4{7⮟o击7QZ;g$HT1Bxk*5µj,' s_%`yǍ^=6Qp,0lojJgX-QUFЊO(܉Iݸ݂\k B-r p_?qXѵÝrƁu^n ,r׫z#NNDDDD>bk{T|Ï^9:ׂX CL\XJZo'm}@Pp x7SݓŽswDDDDD n'zW|.utě3(mE*Kg?.3y?m;p0>p޶YQǽ}{G/G(gy…U^}}q=yq={{ts:.Ak筷xH%)aDDDDDD7UvbT}Jec7fDDDDDD7Up-1nxL;wpj+I-\ul=S ǎ_\ z(zU8q%%^P\K"'""""'ռn |HZpohJ:ג4O)Th:)q8Nm w"""""qr7pcUFtWўajn[.Z8*SSZg{ Rm++I P n_ƍ%7Xo7g|oyr?ō[6hxxcT?FoFDӽcAqsy7V߽? w'p܃}J _ ӫK^o 짢Q>7G!oY;vخ+zmw}rsŔ^9;8,`p&.,o44܌X\XMdKl^y__UZ߂Ǎޱ|kC\<t{}-?Pބ F?[V(x-=Rʋq).[v)'x^4ΣtΩF(܉I%#e-e#825P WK ,.l'l$P~>P ^ w#{+ As\k}wWw\k]SPJ˘ 1eE'—/^nQHۀ809P9>e`=>.>"(OYµ=^Åߢ֏W3^? RYֶs w"""""qp WV]mA]\Ϙ_-cl+Ut=SV{1)GZ^$.#[DDDDD8q-^;fORp;`"QșT9V Vz-n`y B]+kpK o٥bs ߹S*{+?065%3pDLEw܉ O[pU3x\Ս>nXq< )<0׫so\(xu1oفmGwq!Pk[%(O:7_[\oq=],, [f@_sRpx5eVtN5BNDDDD$Nts}7F:my=N* ruHz0-=PxdɫDDDDD$N7#q%*w==նXc,e9<֯pdwv@NDDDD$Nr ߔSЬЬ)uӮ&.,r-w%C]:mRAKNaȲ KHt].) ٤3u&k]DE9!P """"`d)(9|]K'%.p\`יDEDDDD^) ) ٤4%y%."""""B:Uy-u#d躈f)9!˞$:ReY v%."""""JNAhk_~DGꯟn?. wLt}DDDDDѹs C/" :I~g%OzD3z/,y&NRL*|?s C{a-_81uZsrva[9!59shM]7{&|ҜA~=Ԓ9q%Be|]z.ќн9\MSvaG$O JKo[DDDDA04 tM4p]DEDDn :pIENDB`html/index.html0000664000175000017500000002613313743770170013741 0ustar priesgopriesgo NeoFox - NEOantigen Feature tOolboX — Neofox 0.4.0.dev1 documentation

html/install.html0000664000175000017500000003153613743770170014303 0ustar priesgopriesgo Installation instructions — Neofox 0.4.0.dev1 documentation

Installation instructions

This installation instructions were tested on Ubuntu 18.04.

Python 3.7 and R 3.6.0 should be preinstalled.

Set the environment variable pointing to Rscript.

export NEOFOX_RSCRIPT=`which Rscript`

Install Neofox

pip install neofox

Install third-party dependencies

Install BLASTP

The version of BLASTP that was tested is 2.8.1, other versions may work but that is untested.

wget https://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/2.8.1/ncbi-blast-2.8.1+-x64-linux.tar.gz
tar -xvf ncbi-blast-2.8.1+-x64-linux.tar.gz
export NEOFOX_BLASTP=`pwd`/ncbi-blast-2.8.1+/bin/blastp

Install NetMHCpan 4.0

NetMHCpan 4.0 can be downloaded by academic users from https://services.healthtech.dtu.dk/service.php?NetMHCpan-4.0

tar -xvf netMHCpan-4.0a.Linux.tar.gz
cd netMHCpan-4.0
wget http://www.cbs.dtu.dk/services/NetMHCpan-4.0/data.Linux.tar.gz
tar -xvf data.Linux.tar.gz
cd ..
export NEOFOX_NETMHCPAN=`pwd`/netMHCpan-4.0/netMHCpan

Configure NetMHCpan as explained in the file netMHCpan-4.0/netMHCpan-4.0.readme

Install NetMHC2pan 3.2

NetMHC2pan can be downloaded by academic users from https://services.healthtech.dtu.dk/software.php

tar -xvf netMHCIIpan-3.2.Linux.tar.gz
cd netMHCIIpan-3.2
# download the data
wget http://www.cbs.dtu.dk/services/NetMHCIIpan-3.2/data.Linux.tar.gz
tar -xvf data.Linux.tar.gz
cd ..
export NEOFOX_NETMHC2PAN=`pwd`/netMHCIIpan-3.2/netMHCIIpan
# install tcsh shell interpreter if not available yet
sudo apt-get install tcsh

Configure NetMHCpan as explained in the file netMHCIIpan-3.2/netMHCIIpan-3.2.readme

Install MixMHCpred 2.0.1

wget https://github.com/GfellerLab/MixMHCpred/archive/v2.0.1.tar.gz
tar -xvf v2.0.1.tar.gz
export NEOFOX_MIXMHCPRED=`pwd`/MixMHCpred-2.0.1/MixMHCpred

Configure MixMHCpred as explained in the file MixMHCpred-2.0.1/README

Install MixMHC2pred 1.1.3

wget https://github.com/GfellerLab/MixMHC2pred/archive/v1.1.tar.gz
tar -xvf v1.1.tar.gz
export NEOFOX_MIXMHC2PRED=`pwd`/MixMHC2pred-1.1/MixMHC2pred_unix

Configure references

For building the reference data we will need makeblastdb, set the environment variable required for building the reference:

export NEOFOX_MAKEBLASTDB=`pwd`/ncbi-blast-2.8.1+/bin/makeblastdb

netMhcPan, netMhcIIPan and Rscript are also required to install the references, see above.

Run the following to configure nefox:

neofox-configure --reference-folder /your/neofox/folder

Unless indicated to the installer by flag --install-r-dependencies you will need to install manually some R dependencies. These dependencies are the following:

lattice
ggplot2
caret
Peptides
doParallel
gbm
html/models.html0000664000175000017500000001443513743770170014117 0ustar priesgopriesgo Data models — Neofox 0.4.0.dev1 documentation

Data models

Protocol buffers is employed to model Neofox’s input and output data: neoantigens, Major Histocompatibility Complex (MHC) alleles and annotations.

Neofox data models

Protocol buffers documentation

html/_modules/0000775000175000017500000000000013743770171013547 5ustar priesgopriesgohtml/_modules/index.html0000664000175000017500000001221613743770171015546 0ustar priesgopriesgo Overview: module code — Neofox 0.4.0.dev1 documentation html/_modules/neofox/0000775000175000017500000000000013743770171015045 5ustar priesgopriesgohtml/_modules/neofox/model/0000775000175000017500000000000013743770171016145 5ustar priesgopriesgohtml/_modules/neofox/model/neoantigen.html0000664000175000017500000010374513743770171021174 0ustar priesgopriesgo neofox.model.neoantigen — Neofox 0.4.0.dev1 documentation

Source code for neofox.model.neoantigen

# Generated by the protocol buffer compiler.  DO NOT EDIT!
# sources: neoantigen.proto
# plugin: python-betterproto
from dataclasses import dataclass
from typing import List

import betterproto


[docs]class Zygosity(betterproto.Enum): """*The zygosity of a given gene""" # *Two equal copies of the gene HOMOZYGOUS = 0 # *Two different copies of the gene HETEROZYGOUS = 1 # *Only one copy of the gene HEMIZYGOUS = 2 # *No copy of the gene LOSS = 3
[docs]class Mhc1Name(betterproto.Enum): """*Valid names for MHC I classic genes""" A = 0 B = 1 C = 2
[docs]class Mhc2GeneName(betterproto.Enum): """ *Valid names for MHC II classic genes.DRA is not included in this list as it does not have much variability in the population and for our purpose isconsidered constant. """ DRB1 = 0 DPA1 = 1 DPB1 = 2 DQA1 = 3 DQB1 = 4
[docs]class Mhc2Name(betterproto.Enum): """*Valid names for MHC II classic molecules""" DR = 0 DP = 1 DQ = 2
[docs]@dataclass class Transcript(betterproto.Message): # *The transcript identifier to which this neoepitope definition refers # (e.g.: Ensembl transcript id) identifier: str = betterproto.string_field(1) # *The genome assembly to which the gene definition refers to (e.g.: GRCh37, # GRCh38) assembly: str = betterproto.string_field(2) # *The gene symbol or gene identifier, optional as the transcript # unequivocally identifies a gene gene: str = betterproto.string_field(3)
[docs]@dataclass class Mutation(betterproto.Message): # *The aminoacid position within the protein. 1-based, starting in the # N-terminus position: int = betterproto.int32_field(1) # *Sequence of aminoacids for the wild type xmer wild_type_xmer: str = betterproto.string_field(2) # *IUPAC code for the wild type aminoacid in this position wild_type_aminoacid: str = betterproto.string_field(3) # *Sequence of aminoacids for the mutated xmer mutated_xmer: str = betterproto.string_field(4) # *IUPAC code for the mutated aminoacid in this position mutated_aminoacid: str = betterproto.string_field(5) # *The left flanking region of variable size in IUPAC codes left_flanking_region: str = betterproto.string_field(6) # *The size of the left flanking region size_left_flanking_region: int = betterproto.int32_field(7) # *The right flanking region of variable size in IUPAC codes right_flanking_region: str = betterproto.string_field(8) # *The size of the right flanking region size_right_flanking_region: int = betterproto.int32_field(9)
[docs]@dataclass class Neoantigen(betterproto.Message): """*A neoantigen minimal definition""" # *A unique identifier of a neoantigen identifier: str = betterproto.string_field(1) # *Patient identifier patient_identifier: str = betterproto.string_field(2) # *The transcript where the neoepitope was observed transcript: "Transcript" = betterproto.message_field(3) # *The mutation mutation: "Mutation" = betterproto.message_field(4) # *Clonality estimation. At the moment this is a boolean indicating whether # there is clonality or not,there is no quantitive measurement at the moment. clonality_estimation: bool = betterproto.bool_field(5) # *Expression value of the transcript from RNA data. Range [0, +inf]. rna_expression: float = betterproto.float_field(6) # *Variant allele frequency from the DNA. Range [0.0, 1.0] dna_variant_allele_frequency: float = betterproto.float_field(7) # *Variant allele frequency from the RNA. Range [0.0, 1.0] rna_variant_allele_frequency: float = betterproto.float_field(8)
[docs]@dataclass class Patient(betterproto.Message): """ *The metadata required for analysis for a given patient + its patient identifier """ # *Patient identifier identifier: str = betterproto.string_field(1) # *Is RNA expression available? is_rna_available: bool = betterproto.bool_field(2) # *MHC I classic molecules mhc1: List["Mhc1"] = betterproto.message_field(3) # *MHC II classic molecules mhc2: List["Mhc2"] = betterproto.message_field(4)
[docs]@dataclass class Annotation(betterproto.Message): """*This is a generic class to hold annotations from Neofox""" # *The name of the annotation name: str = betterproto.string_field(1) # *The value of the annotationTODO: make this better to hold int, float and # bool value: str = betterproto.string_field(2)
[docs]@dataclass class NeoantigenAnnotations(betterproto.Message): """*A set of annotations for a neoantigen""" # *A unique identifier of a neoantigen neoantigen_identifier: str = betterproto.string_field(1) # *List of annotations annotations: List["Annotation"] = betterproto.message_field(2) # *The annotator annotator: str = betterproto.string_field(3) # *The version of the annotator annotator_version: str = betterproto.string_field(4) # *A timestamp determined when the annotation was created timestamp: str = betterproto.string_field(5) # *Annotation resources MD5 hash resources_hash: str = betterproto.string_field(6)
[docs]@dataclass class Mhc1(betterproto.Message): """ *Models MHC I alleles related to the same MHC I gene, i.e. 2 alleles/2 isoforms per gene """ # *MHC I gene name name: "Mhc1Name" = betterproto.enum_field(1) # *Zygosity of the gene zygosity: "Zygosity" = betterproto.enum_field(2) # *The alleles of the gene (0, 1 or 2) alleles: List["MhcAllele"] = betterproto.message_field(3)
[docs]@dataclass class Mhc2(betterproto.Message): """ *Models MHC II alleles related to the same MHC II protein, i.e. 4 isoforms related to 2 genes with 2 alleles each """ # *MHC II molecule name name: "Mhc2Name" = betterproto.enum_field(1) # *List of MHC II genes genes: List["Mhc2Gene"] = betterproto.message_field(2) # *Different combinations of MHC II alleles building different isoforms isoforms: List["Mhc2Isoform"] = betterproto.message_field(3)
[docs]@dataclass class Mhc2Isoform(betterproto.Message): """*MHC II isoform""" # *Name to refer to the MHC II isoform name: str = betterproto.string_field(1) # *The alpha chain of the isoform alpha_chain: "MhcAllele" = betterproto.message_field(2) # *The beta chain of the isoform beta_chain: "MhcAllele" = betterproto.message_field(3)
[docs]@dataclass class Mhc2Gene(betterproto.Message): """*MHC II gene""" # *MHC II gene name name: "Mhc2GeneName" = betterproto.enum_field(1) # *Zygosity of the gene zygosity: "Zygosity" = betterproto.enum_field(2) # *The alleles of the gene (0, 1 or 2) alleles: List["MhcAllele"] = betterproto.message_field(3)
[docs]@dataclass class MhcAllele(betterproto.Message): """ *MHC allele representation. It does not include non synonymous changes to the sequence, changes in the non coding regionor changes in expression. See http://hla.alleles.org/nomenclature/naming.html for details """ # *HLA full name as provided by the user (e.g.: HLA-DRB1*13:01:02:03N). This # will be parsed into name, gene and group.Any digit format is allowed for # this field (ie: 4, 6 or 8 digits), 2 digits names are not specific enough # for ourpurpose and thus invalid full_name: str = betterproto.string_field(1) # *A specific HLA protein (e.g. HLA-DRB1*13:01). Alleles whose numbers differ # in group and protein must differ in oneor more nucleotide substitutions # that change the amino acid sequence of the encoded protein.This name is # normalized to avoid different representations of the same allele. For # instance both HLA-DRB113:01 andHLA-DRB1*13:01:02:03N will be transformed # into their normalised version HLA-DRB1*13:01. This name is also truncatedto # 4 digits. 2 digits names are not specific enough for our purpose and thus # invalid name: str = betterproto.string_field(2) # *The gene from either MHC I or II (e.g. DRB1, A) (this information is # redundant with the Mhc1Gene.name andMhc2Gene.name but it is convenient to # have this at this level too, code will check for data coherence) gene: str = betterproto.string_field(3) # *A group of alleles defined by a common serotype ie: Serological antigen # carried by an allotype (e.g. 13 from HLA-DRB1*13) group: str = betterproto.string_field(4) # *A specific protein (e.g.: 02 from HLA-DRB1*13:02) protein: str = betterproto.string_field(5)
html/_modules/neofox/model/conversion.html0000664000175000017500000023421413743770171021226 0ustar priesgopriesgo neofox.model.conversion — Neofox 0.4.0.dev1 documentation

Source code for neofox.model.conversion

#
# Copyright (c) 2020-2030 Translational Oncology at the Medical Center of the Johannes Gutenberg-University Mainz gGmbH.
#
# This file is part of Neofox
# (see https://github.com/tron-bioinformatics/neofox).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.#
from typing import List

import pandas as pd
import betterproto
from betterproto import Casing
from pandas.io.json import json_normalize
import re
import difflib
from collections import defaultdict
import json
from neofox.model.neoantigen import Neoantigen, Transcript, Mutation, Patient, NeoantigenAnnotations, Mhc2Name, \
    Mhc2GeneName, Zygosity, Mhc2Gene, Mhc2, Mhc2Isoform, MhcAllele, Mhc1Name, Mhc1

FIELD_SUBSTITUTION = 'substitution'

FIELD_VAF_DNA = 'VAF_in_tumor'
FIELD_VAF_RNA = 'VAF_in_RNA'
FIELD_RNA_EXPRESSION = 'VAF_RNA_raw'
FIELD_TRANSCRIPT_EXPRESSION = 'transcript_expression'
FIELD_TRANSCRIPT = 'UCSC_transcript'
FIELD_GENE = 'gene'
FIELD_WILD_TYPE_XMER = '[WT]_+-13_AA_(SNV)_/_-15_AA_to_STOP_(INDEL)'
FIELD_MUTATED_XMER = '+-13_AA_(SNV)_/_-15_AA_to_STOP_(INDEL)'


[docs]class ModelConverter(object): HLA_ALLELE_PATTERN = re.compile( r"(?:HLA-)?([A-Z0-9]+)[\*|_]?([0-9]{2}):?([0-9]{2,}):?([0-9]{2,})?:?([0-9]{2,})?([N|L|S|Q]{0,1})") HLA_MOLECULE_PATTERN = re.compile(r"(?:HLA-)?([A-Z0-9]+[\*|_]?[0-9]{2,}:?[0-9]{2,})-" r"([A-Z0-9]+[\*|_]?[0-9]{2,}:?[0-9]{2,})") HLA_DR_MOLECULE_PATTERN = re.compile(r"(?:HLA-)?(DRB1[\*|_]?[0-9]{2,}:?[0-9]{2,})") GENES_BY_MOLECULE = { Mhc2Name.DR: [Mhc2GeneName.DRB1], Mhc2Name.DP: [Mhc2GeneName.DPA1, Mhc2GeneName.DPB1], Mhc2Name.DQ: [Mhc2GeneName.DQA1, Mhc2GeneName.DQB1], }
[docs] @staticmethod def parse_candidate_file(candidate_file: str, patient_id: str = None) -> List[Neoantigen]: """ :param candidate_file: the path to an neoantigen candidate input file :param patient_id: the patient identifier for all neoantigens in the input file, if not provided it is expected as column named `patient.id` or `patient` :return neoantigens in model objects """ data = pd.read_csv(candidate_file, sep='\t') # filter out indels data = data[~data['substitution'].isna()] ModelConverter._enrich_candidate_table(data) neoantigens = [] for _, candidate_entry in data.iterrows(): neoantigens.append(ModelConverter._candidate_entry2model(candidate_entry, patient_id=patient_id)) return neoantigens
[docs] @staticmethod def parse_patients_file(patients_file: str) -> List[Patient]: """ :param patients_file: the file to patients data CSV file :return: the parsed CSV into model objects """ split_comma_separated_list = lambda x: x.split(',') df = pd.read_csv( patients_file, sep='\t', converters={'mhcIAlleles': split_comma_separated_list, 'mhcIIAlleles': split_comma_separated_list}) return ModelConverter.patient_metadata_csv2objects(df)
[docs] @staticmethod def parse_neoantigens_file(neoantigens_file: str) -> List[Neoantigen]: """ :param neoantigens_file: the file to neoantigens data CSV file :return: the parsed CSV into model objects """ return ModelConverter.neoantigens_csv2objects(pd.read_csv(neoantigens_file, sep='\t').fillna(""))
[docs] @staticmethod def objects2dataframe(model_objects: List[betterproto.Message]) -> pd.DataFrame: """ :param model_objects: list of objects of subclass of betterproto.Message """ return json_normalize(data=[n.to_dict(include_default_values=True) for n in model_objects])
[docs] @staticmethod def objects2json(model_objects: List[betterproto.Message], output_file: str): """ :param model_objects: list of objects of subclass of betterproto.Message """ with open(output_file, "w") as f: json.dump([o.to_dict(casing=Casing.SNAKE) for o in model_objects], f)
[docs] @staticmethod def object2series(model_object: betterproto.Message) -> pd.Series: """ :param model_object: object of subclass of betterproto.Message """ return json_normalize(data=model_object.to_dict(casing=Casing.SNAKE, include_default_values=True)).iloc[0]
[docs] @staticmethod def object2flat_dict(model: betterproto.Message) -> dict: """ Transforms a model object into a flat dict. Nested fields are concatenated with a dot """ return ModelConverter.object2series(model).to_dict()
[docs] @staticmethod def neoantigens_csv2object(series: pd.Series) -> Neoantigen: """transforms an entry from a CSV into an object""" return Neoantigen().from_dict(ModelConverter._flat_dict2nested_dict(flat_dict=series.to_dict()))
[docs] @staticmethod def patient_metadata_csv2objects(dataframe: pd.DataFrame) -> List[Patient]: """transforms an patients CSV into a list of objects""" patients = [] for _, row in dataframe.iterrows(): patient_dict = row.to_dict() patient = Patient().from_dict(patient_dict) patient.mhc1 = ModelConverter.parse_mhc1_alleles(patient_dict['mhcIAlleles']) patient.mhc2 = ModelConverter.parse_mhc2_alleles(patient_dict['mhcIIAlleles']) patients.append(patient) return patients
[docs] @staticmethod def neoantigens_csv2objects(dataframe: pd.DataFrame) -> List[Neoantigen]: """transforms an patients CSV into a list of objects""" neoantigens = [] for _, row in dataframe.iterrows(): neoantigens.append(Neoantigen().from_dict(ModelConverter._flat_dict2nested_dict(flat_dict=row.to_dict()))) return neoantigens
[docs] @staticmethod def annotations2short_wide_table( neoantigen_annotations: List[NeoantigenAnnotations], neoantigens: List[Neoantigen]) -> pd.DataFrame: dfs = [] neoantigens_df = ModelConverter.objects2dataframe(neoantigens) for na in neoantigen_annotations: df = pd.DataFrame([a.to_dict() for a in na.annotations]).set_index('name').transpose() df['identifier'] = na.neoantigen_identifier df.reset_index(inplace=True) del df['index'] dfs.append(df) annotations_df = pd.concat(dfs) return neoantigens_df.set_index('identifier').merge(annotations_df, on='identifier')
[docs] @staticmethod def annotations2tall_skinny_table(neoantigen_annotations: List[NeoantigenAnnotations]) -> pd.DataFrame: dfs = [] for na in neoantigen_annotations: df = pd.DataFrame([a.to_dict() for a in na.annotations]) df['neoantigen_identifier'] = na.neoantigen_identifier dfs.append(df[df.value != "NA"]) # avoid writing NA values return pd.concat(dfs)
@staticmethod def _flat_dict2nested_dict(flat_dict: dict) -> dict: """transforms a flattened dict into a nested dict, assuming that the dot indicates a nested level""" nested_dict = defaultdict(lambda: {}) for k, v in flat_dict.items(): splitted_k = k.split('.') if len(splitted_k) > 2: raise NotImplemented("Support for dictionaries nested more than one level is not implemented") if len(splitted_k) == 2: nested_dict[splitted_k[0]][splitted_k[1]] = v else: nested_dict[k] = v return dict(nested_dict) @staticmethod def _candidate_entry2model(candidate_entry: dict, patient_id: str) -> Neoantigen: """parses an row from a candidate file into a model object""" transcript = Transcript() transcript.assembly = 'hg19' transcript.gene = candidate_entry.get(FIELD_GENE) transcript.identifier = candidate_entry.get(FIELD_TRANSCRIPT) mutation = Mutation() mutation.position = candidate_entry.get('position') mutation.wild_type_aminoacid = candidate_entry.get('wild_type_aminoacid') mutation.mutated_aminoacid = candidate_entry.get('mutated_aminoacid') mutation.left_flanking_region = candidate_entry.get('left_flanking_region') mutation.right_flanking_region = candidate_entry.get('right_flanking_region') neoantigen = Neoantigen() neoantigen.patient_identifier = patient_id if patient_id else candidate_entry.get('patient') neoantigen.mutation = mutation neoantigen.transcript = transcript # clonality estimation is not present in candidate file at the moment neoantigen.clonality_estimation = None # missing RNA expression values are represented as -1 vaf_rna_raw = candidate_entry.get(FIELD_TRANSCRIPT_EXPRESSION) neoantigen.rna_expression = vaf_rna_raw if vaf_rna_raw >= 0 else None vaf_in_rna = candidate_entry.get(FIELD_VAF_RNA) neoantigen.rna_variant_allele_frequency = vaf_in_rna if vaf_in_rna >= 0 else None neoantigen.dna_variant_allele_frequency = candidate_entry.get(FIELD_VAF_DNA) return neoantigen @staticmethod def _enrich_candidate_table(data: pd.DataFrame): """parses some data from the candidate table into the right fields in the model objects""" data['wild_type_aminoacid'] = data[FIELD_SUBSTITUTION].transform(lambda x: re.search("(\w)\d+\w", x).group(1)) data['mutated_aminoacid'] = data[FIELD_SUBSTITUTION].transform(lambda x: re.search("\w\d+(\w)", x).group(1)) data['position'] = data[FIELD_SUBSTITUTION].transform(lambda x: int(re.search("\w(\d+)\w", x).group(1))) data['left_flanking_region'] = data[[ FIELD_MUTATED_XMER, FIELD_WILD_TYPE_XMER]].apply( lambda x: ModelConverter._get_matching_region(x[0], x[1]), axis=1) data['right_flanking_region'] = data[[ FIELD_MUTATED_XMER, FIELD_WILD_TYPE_XMER]].apply( lambda x: ModelConverter._get_matching_region(x[0], x[1], match=1), axis=1) @staticmethod def _get_matching_region(sequence1: str, sequence2: str, match: int = 0) -> str: """fetches an aligned block within two sequences""" match = difflib.SequenceMatcher(None, sequence1, sequence2).get_matching_blocks()[match] return sequence1[match.a : match.a + match.size]
[docs] @staticmethod def parse_mhc1_alleles(alleles: List[str]) -> List[Mhc1]: isoforms = [] parsed_alleles = list(map(ModelConverter.parse_mhc_allele, alleles)) ModelConverter._validate_mhc1_alleles(parsed_alleles) # do we need to validate genes anymore? add test creating MhcAllele with bad gene and see what happens for gene_name in Mhc1Name: gene_alleles = list(filter(lambda a: a.gene == gene_name.name, parsed_alleles)) zygosity = ModelConverter._get_zygosity_from_alleles(gene_alleles) if zygosity == Zygosity.HOMOZYGOUS: gene_alleles = [gene_alleles[0]] # we don't want repeated instances of the same allele isoforms.append(Mhc1(name=gene_name, zygosity=zygosity, alleles=gene_alleles)) return isoforms
[docs] @staticmethod def parse_mhc2_alleles(alleles: List[str]) -> List[Mhc2]: mhc2s = [] parsed_alleles = list(map(ModelConverter.parse_mhc_allele, alleles)) ModelConverter._validate_mhc2_alleles(parsed_alleles) # do we need to validate genes anymore? add test creating MhcAllele with bad gene and see what happens for isoform_name in Mhc2Name: isoform_alleles = list(filter(lambda a: isoform_name.name in a.gene, parsed_alleles)) genes = [] for gene_name in ModelConverter.GENES_BY_MOLECULE.get(isoform_name): gene_alleles = list(filter(lambda a: a.gene == gene_name.name, isoform_alleles)) zygosity = ModelConverter._get_zygosity_from_alleles(gene_alleles) if zygosity == Zygosity.HOMOZYGOUS: gene_alleles = [gene_alleles[0]] # we don't want repeated instances of the same allele genes.append(Mhc2Gene(name=gene_name, zygosity=zygosity, alleles=gene_alleles)) isoforms = ModelConverter._get_mhc2_isoforms(isoform_name, genes) mhc2s.append(Mhc2(name=isoform_name, genes=genes, isoforms=isoforms)) return mhc2s
@staticmethod def _get_mhc2_isoforms(isoform_name: Mhc2Name, genes: List[Mhc2Gene]) -> List[Mhc2Isoform]: isoforms = [] if isoform_name == Mhc2Name.DR: assert len(genes) <= 1, "More than one gene provided for MHC II DR" # alpha chain of the MHC II DR is not modelled as it is constant isoforms = [Mhc2Isoform(name=a.name, alpha_chain=None, beta_chain=a) for g in genes for a in g.alleles] elif isoform_name == Mhc2Name.DP: assert len(genes) <= 2, "More than two genes provided for MHC II DP" alpha_alleles = [a for g in genes if g.name == Mhc2GeneName.DPA1 for a in g.alleles] beta_alleles = [a for g in genes if g.name == Mhc2GeneName.DPB1 for a in g.alleles] isoforms = [Mhc2Isoform(name=ModelConverter.get_mhc2_isoform_name(a, b), alpha_chain=a, beta_chain=b) for a in alpha_alleles for b in beta_alleles] elif isoform_name == Mhc2Name.DQ: assert len(genes) <= 2, "More than two genes provided for MHC II DQ" alpha_alleles = [a for g in genes if g.name == Mhc2GeneName.DQA1 for a in g.alleles] beta_alleles = [a for g in genes if g.name == Mhc2GeneName.DQB1 for a in g.alleles] isoforms = [Mhc2Isoform(name=ModelConverter.get_mhc2_isoform_name(a, b), alpha_chain=a, beta_chain=b) for a in alpha_alleles for b in beta_alleles] return isoforms
[docs] @staticmethod def get_mhc2_isoform_name(a: MhcAllele, b: MhcAllele): # NOTE: this is needed as jus setting alpha chain to None wouldn't work with protobuf if a is not None and a.name: return "{}-{}".format(a.name, b.name.replace("HLA-", "")) else: return b.name
[docs] @staticmethod def parse_mhc_allele(allele: str) -> MhcAllele: # infers gene, group and protein from the name match = ModelConverter.HLA_ALLELE_PATTERN.match(allele) assert match is not None, "Allele does not match HLA allele pattern {}".format(allele) gene = match.group(1) group = match.group(2) protein = match.group(3) # builds a normalized representation of the allele name = "HLA-{gene}*{serotype}:{protein}".format(gene=gene, serotype=group, protein=protein) # ensures that full name stores the complete allele as provided but normalizes # its representation full_name = name six_digits_id = match.group(4) if six_digits_id is not None and six_digits_id != "": full_name = full_name + ":{}".format(six_digits_id) eight_digits_id = match.group(5) if eight_digits_id is not None and eight_digits_id != "": full_name = full_name + ":{}".format(eight_digits_id) expression_change = match.group(6) if expression_change is not None and expression_change != "": full_name = full_name + expression_change return MhcAllele(full_name=full_name, name=name, gene=gene, group=group, protein=protein)
@staticmethod def _get_zygosity_from_alleles(alleles: List[MhcAllele]) -> Zygosity: assert len(set([a.gene for a in alleles])) <= 1, "Trying to get zygosity from alleles of different genes" assert len(alleles) <= 2, "More than 2 alleles for gene {}".format(alleles[0].gene) if len(alleles) == 2 and alleles[0].name == alleles[1].name: zygosity = Zygosity.HOMOZYGOUS elif len(alleles) == 2: zygosity = Zygosity.HETEROZYGOUS elif len(alleles) == 1: zygosity = Zygosity.HEMIZYGOUS else: zygosity = Zygosity.LOSS return zygosity @staticmethod def _validate_mhc1_alleles(parsed_alleles: List[MhcAllele]): for a in parsed_alleles: assert a.gene in Mhc1Name.__members__, "Gene from MHC I allele is not valid: {}".format(a.gene) @staticmethod def _validate_mhc2_alleles(parsed_alleles: List[MhcAllele]): for a in parsed_alleles: assert a.gene in Mhc2GeneName.__members__, "Gene from MHC II allele is not valid: {}".format(a.gene)
html/_modules/neofox/model/wrappers.html0000664000175000017500000002610013743770171020675 0ustar priesgopriesgo neofox.model.wrappers — Neofox 0.4.0.dev1 documentation

Source code for neofox.model.wrappers

#
# Copyright (c) 2020-2030 Translational Oncology at the Medical Center of the Johannes Gutenberg-University Mainz gGmbH.
#
# This file is part of Neofox
# (see https://github.com/tron-bioinformatics/neofox).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.#
from typing import List
from neofox.model.neoantigen import Annotation, Mhc2, Mhc2GeneName, MhcAllele

NOT_AVAILABLE_VALUE = "NA"


[docs]class AnnotationFactory(object):
[docs] @staticmethod def build_annotation(name, value): if isinstance(value, bool): # prints booleans as 0/1 strings value = "1" if value else "0" if not isinstance(value, str) and not isinstance(value, type(None)): if isinstance(value, float): value = "{0:.5g}".format(round(value, 5)) else: value = str(value) if value is None: value = NOT_AVAILABLE_VALUE return Annotation(name=name, value=value)
[docs]def get_alleles_by_gene(mhc_isoforms: List[Mhc2], gene: Mhc2GeneName) -> List[MhcAllele]: return [a for m in mhc_isoforms for g in m.genes if g.name == gene for a in g.alleles]
html/_modules/neofox/model/validation.html0000664000175000017500000020131513743770171021167 0ustar priesgopriesgo neofox.model.validation — Neofox 0.4.0.dev1 documentation

Source code for neofox.model.validation

#
# Copyright (c) 2020-2030 Translational Oncology at the Medical Center of the Johannes Gutenberg-University Mainz gGmbH.
#
# This file is part of Neofox
# (see https://github.com/tron-bioinformatics/neofox).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.#
import base64
import hashlib
import betterproto
from neofox.model.conversion import ModelConverter
from neofox.exceptions import NeofoxDataValidationException
from neofox.model.neoantigen import Neoantigen, Mutation, Transcript, Patient, MhcAllele, Mhc2Isoform, Mhc1, \
    Mhc1Name, Zygosity, Mhc2, Mhc2Name, Mhc2GeneName
from Bio.Alphabet.IUPAC import ExtendedIUPACProtein, IUPACData


[docs]class ModelValidator(object):
[docs] @staticmethod def validate(model: betterproto.Message): # TODO: make this method capture appropriately validation issues whend dealing with int and float try: model.__bytes__() except Exception as e: raise NeofoxDataValidationException(e)
# TODO: add patient validation: validate GTEx tissue and MHC alleles
[docs] @staticmethod def validate_neoantigen(neoantigen: Neoantigen) -> Neoantigen: # checks format consistency first ModelValidator.validate(neoantigen) try: # checks gene # TODO: do we want to verify existence of gene and transcript id? neoantigen.transcript = ModelValidator._validate_transcript(neoantigen.transcript) # checks mutation neoantigen.mutation = ModelValidator._validate_mutation(neoantigen.mutation) # check the expression values ModelValidator._validate_expression_values(neoantigen) except AssertionError as e: raise NeofoxDataValidationException(e) # infer other fields from the model return ModelValidator._enrich_neoantigen(neoantigen)
[docs] @staticmethod def validate_patient(patient: Patient) -> Patient: # checks format consistency first ModelValidator.validate(patient) try: # checks that patient id is not empty considering white spaces patient_id = patient.identifier.strip() if patient.identifier else patient.identifier assert patient_id is not None and patient_id != "", "Patient identifier is empty" patient.identifier = patient_id # TODO: validate new model with isoforms, genes and alleles # checks MHC I validated_mhc1s = [] for m in patient.mhc1: validated_mhc1s.append(ModelValidator._validate_mhc1(m)) patient.mhc1 = validated_mhc1s # checks MHC II validated_mhc2s = [] for m in patient.mhc2: validated_mhc2s.append(ModelValidator._validate_mhc2(m)) patient.mhc2 = validated_mhc2s except AssertionError as e: raise NeofoxDataValidationException(e) return patient
@staticmethod def _validate_mhc1(mhc1: Mhc1) -> Mhc1: assert mhc1.name in Mhc1Name, "Invalid MHC I name" assert mhc1.zygosity in Zygosity, "Invalid zygosity" alleles = mhc1.alleles if mhc1.zygosity in [Zygosity.HOMOZYGOUS, Zygosity.HEMIZYGOUS]: assert len(alleles) == 1, "An homozygous gene must have 1 allele and not {}".format(len(alleles)) elif mhc1.zygosity == Zygosity.HETEROZYGOUS: assert len(alleles) == 2, "An heterozygous or hemizygous gene must have 2 alleles and not {}".format( len(alleles)) elif mhc1.zygosity == Zygosity.LOSS: assert len(alleles) == 0, "An lost gene must have 0 alleles and not {}".format( len(alleles)) validated_alleles = [] for allele in alleles: validated_allele = ModelValidator.validate_mhc_allele_representation(allele) validated_alleles.append(validated_allele) assert validated_allele.gene == mhc1.name.name, \ "The allele referring to gene {} is inside gene {}".format(validated_allele.gene, mhc1.name.name) mhc1.alleles = validated_alleles return mhc1 @staticmethod def _validate_mhc2(mhc2: Mhc2) -> Mhc2: assert mhc2.name in Mhc2Name, "Invalid MHC II name" genes = mhc2.genes for gene in genes: assert gene.name in Mhc2GeneName, "Invalid gene name from MHC II" assert gene.name in ModelConverter.GENES_BY_MOLECULE.get(mhc2.name), \ "Gene {} referring to isoform {}".format(gene.name, mhc2.name.name) assert gene.zygosity in Zygosity, "Invalid zygosity" alleles = gene.alleles if gene.zygosity == Zygosity.HOMOZYGOUS: assert len(alleles) == 1, "An homozygous gene must have 1 allele and not {}".format(len(alleles)) elif gene.zygosity in [Zygosity.HETEROZYGOUS, Zygosity.HEMIZYGOUS]: assert len(alleles) == 2, "An heterozygous or hemizygous gene must have 2 alleles and not {}".format( len(alleles)) elif gene.zygosity == Zygosity.LOSS: assert len(alleles) == 0, "An lost gene must have 0 alleles and not {}".format( len(alleles)) validated_alleles = [] for allele in alleles: validated_allele = ModelValidator.validate_mhc_allele_representation(allele) validated_alleles.append(validated_allele) assert validated_allele.gene == gene.name.name, \ "The allele referring to gene {} is inside gene {}".format(validated_allele.gene, gene.name.name) gene.alleles = validated_alleles isoforms = mhc2.isoforms validated_isoforms = [] for isoform in isoforms: validated_isoform = ModelValidator.validate_mhc2_isoform_representation(isoform) validated_isoforms.append(validated_isoform) if mhc2.name != Mhc2Name.DR: assert validated_isoform.alpha_chain.name in [a.name for g in genes for a in g.alleles], \ "Alpha chain allele not present in th list of alleles" assert validated_isoform.beta_chain.name in [a.name for g in genes for a in g.alleles], \ "Beta chain allele not present in th list of alleles" mhc2.isoforms = validated_isoforms return mhc2
[docs] @staticmethod def validate_mhc_allele_representation(allele: MhcAllele) -> MhcAllele: try: full_name = None if allele.full_name: # infers gene, group and protein from the name match = ModelConverter.HLA_ALLELE_PATTERN.match(allele.full_name) assert match is not None, "Allele does not match HLA allele pattern {}".format(allele.name) gene = match.group(1) group = match.group(2) protein = match.group(3) full_name = allele.full_name elif allele.name: # infers gene, group and protein from the name match = ModelConverter.HLA_ALLELE_PATTERN.match(allele.name) assert match is not None, "Allele does not match HLA allele pattern {}".format(allele.name) gene = match.group(1) group = match.group(2) protein = match.group(3) elif allele.gene and allele.group and allele.protein: # infers name from gene, group and protein gene = allele.gene group = allele.group protein = allele.protein else: raise NeofoxDataValidationException( "HLA allele missing required fields, either name or gene, group and protein must be provided") assert gene in list(Mhc1Name.__members__.keys()) + list(Mhc2GeneName.__members__.keys()), \ "Gene not from classic MHC: {}".format(gene) # builds the final allele representation and validates it just in case name = "HLA-{gene}*{serotype}:{protein}".format(gene=gene, serotype=group, protein=protein) match = ModelConverter.HLA_ALLELE_PATTERN.match(name) assert match is not None, "Allele does not match HLA allele pattern {}".format(name) except AssertionError as e: raise NeofoxDataValidationException(e) return MhcAllele(full_name=full_name if full_name else name, name=name, gene=gene, group=group, protein=protein)
[docs] @staticmethod def validate_mhc2_isoform_representation(isoform: Mhc2Isoform) -> Mhc2Isoform: try: if isoform.name: # infers alpha and beta chains match = ModelConverter.HLA_MOLECULE_PATTERN.match(isoform.name) if match: alpha_chain = ModelValidator.validate_mhc_allele_representation(MhcAllele(name=match.group(1))) beta_chain = ModelValidator.validate_mhc_allele_representation(MhcAllele(name=match.group(2))) else: match = ModelConverter.HLA_DR_MOLECULE_PATTERN.match(isoform.name) assert match is not None, "Molecule does not match HLA isoform pattern {}".format(isoform.name) alpha_chain = MhcAllele() beta_chain = ModelValidator.validate_mhc_allele_representation(MhcAllele(name=match.group(1))) elif isoform.alpha_chain and isoform.beta_chain: # infers name from gene, group and protein alpha_chain = ModelValidator.validate_mhc_allele_representation(isoform.alpha_chain) beta_chain = ModelValidator.validate_mhc_allele_representation(isoform.beta_chain) else: raise NeofoxDataValidationException("HLA isoform missing required fields") # builds the final allele representation and validates it just in case name = ModelConverter.get_mhc2_isoform_name(alpha_chain, beta_chain) match = ModelConverter.HLA_MOLECULE_PATTERN.match(name) match2 = ModelConverter.HLA_DR_MOLECULE_PATTERN.match(name) assert match is not None or match2 is not None, \ "Molecule does not match HLA isoform pattern {}".format(name) except AssertionError as e: raise NeofoxDataValidationException(e) return Mhc2Isoform(name=name, alpha_chain=alpha_chain, beta_chain=beta_chain)
@staticmethod def _validate_expression_values(neoantigen): assert neoantigen.rna_expression is None or neoantigen.rna_expression >= 0, \ "RNA expression should be a positive integer or zero {}".format(neoantigen.rna_expression) ModelValidator._validate_vaf(neoantigen.dna_variant_allele_frequency) ModelValidator._validate_vaf(neoantigen.rna_variant_allele_frequency) @staticmethod def _validate_mutation(mutation: Mutation) -> Mutation: # checks aminoacids mutation.mutated_aminoacid = ModelValidator._validate_aminoacid(mutation.mutated_aminoacid) mutation.wild_type_aminoacid = ModelValidator._validate_aminoacid(mutation.wild_type_aminoacid) # checks left and right flanking regions assert mutation.left_flanking_region is not None, "Empty left flanking region" mutation.left_flanking_region = mutation.left_flanking_region.strip() assert len(mutation.left_flanking_region) > 0, "Empty left flanking region" for aa in mutation.left_flanking_region: ModelValidator._validate_aminoacid(aa) assert mutation.right_flanking_region is not None, "Empty right flanking region" mutation.right_flanking_region = mutation.right_flanking_region.strip() assert len(mutation.right_flanking_region) > 0, "Empty right flanking region" for aa in mutation.right_flanking_region: ModelValidator._validate_aminoacid(aa) # checks the position assert mutation.position is not None, "Empty position" assert isinstance(mutation.position, int), "Position must be an integer" assert mutation.position > 0, "Position must be a 1-based positive integer" return mutation @staticmethod def _validate_transcript(transcript: Transcript) -> Transcript: # TODO: validate that gene symbol exists gene_name = transcript.gene.strip() if transcript.gene else transcript.gene assert gene_name is not None and len(gene_name) > 0, "Empty gene symbol" transcript.gene = gene_name # TODO: validate that transcript identifier exists transcript_identifier = transcript.identifier.strip() if transcript.identifier else transcript.identifier assert transcript_identifier is not None and len(transcript_identifier) > 0, "Empty transcript identifier" transcript.identifier = transcript_identifier # TODO: support other assemblies assembly = transcript.assembly if transcript.assembly else "hg19" assert assembly == "hg19", "Other reference genome than hg19 is not supported" transcript.assembly = assembly return transcript @staticmethod def _validate_vaf(vaf): assert vaf is None or 0.0 <= vaf <= 1.0, "VAF should be a positive integer or zero {}".format(vaf) @staticmethod def _enrich_neoantigen(neoantigen: Neoantigen) -> Neoantigen: neoantigen.mutation.wild_type_xmer = "".join([ neoantigen.mutation.left_flanking_region, neoantigen.mutation.wild_type_aminoacid, neoantigen.mutation.right_flanking_region]) neoantigen.mutation.mutated_xmer = "".join([ neoantigen.mutation.left_flanking_region, neoantigen.mutation.mutated_aminoacid, neoantigen.mutation.right_flanking_region]) neoantigen.mutation.size_left_flanking_region = len(neoantigen.mutation.left_flanking_region) neoantigen.mutation.size_right_flanking_region = len(neoantigen.mutation.right_flanking_region) neoantigen.identifier = ModelValidator.generate_neoantigen_identifier(neoantigen) return neoantigen @staticmethod def _validate_aminoacid(aminoacid): assert aminoacid is not None, "Aminoacid field cannot be empty" aminoacid = aminoacid.strip() assert isinstance(aminoacid, str), "Aminoacid has to be a string" if len(aminoacid) == 3: assert aminoacid in IUPACData.protein_letters_3to1_extended.keys(), \ "Non existing 3 letter aminoacid {}".format(aminoacid) aminoacid = IUPACData.protein_letters_3to1_extended.get(aminoacid) if len(aminoacid) == 1: assert aminoacid in ExtendedIUPACProtein.letters, "Non existing aminoacid {}".format(aminoacid) else: assert False, "Invalid aminoacid {}".format(aminoacid) return aminoacid
[docs] @staticmethod def generate_neoantigen_identifier(neoantigen: Neoantigen) -> str: neoantigen.identifier = None # this needs to be done otherwise we cannot rreproduce the id after it is set return base64.b64encode(hashlib.md5(neoantigen.to_json().encode('utf8')).digest()).decode('utf8')
html/_modules/neofox/neofox.html0000664000175000017500000006670613743770171017250 0ustar priesgopriesgo neofox.neofox — Neofox 0.4.0.dev1 documentation

Source code for neofox.neofox

#!/usr/bin/env python
#
# Copyright (c) 2020-2030 Translational Oncology at the Medical Center of the Johannes Gutenberg-University Mainz gGmbH.
#
# This file is part of Neofox
# (see https://github.com/tron-bioinformatics/neofox).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.#
import logging
import os
import time
from typing import List
import logzero
from logzero import logger
from dask.distributed import Client

from neofox.references.references import ReferenceFolder, AvailableAlleles, DependenciesConfiguration

from neofox import NEOFOX_LOG_FILE_ENV
from neofox.annotator import NeoantigenAnnotator
from neofox.exceptions import NeofoxConfigurationException, NeofoxDataValidationException
from neofox.model.neoantigen import NeoantigenAnnotations, Neoantigen, Patient
from neofox.model.validation import ModelValidator


[docs]class NeoFox: def __init__(self, neoantigens: List[Neoantigen], patient_id: str, patients: List[Patient], num_cpus: int, work_folder=None, output_prefix=None, reference_folder: ReferenceFolder = None, configuration: DependenciesConfiguration = None): # initialise logs self._initialise_logs(output_prefix, work_folder) # initialise dask # TODO: number of threads is hard coded. Is there a better value for this? self.dask_client = Client(processes=True, n_workers=num_cpus, threads_per_worker=4) # intialize references folder and configuration # NOTE: uses the reference folder and config passed as a parameter if exists, this is here to make it # testable with fake objects self.reference_folder = reference_folder if reference_folder else ReferenceFolder() self.configuration = configuration if configuration else DependenciesConfiguration() if neoantigens is None or len(neoantigens) == 0 or patients is None or len(patients) == 0: raise NeofoxConfigurationException("Missing input data to run Neofox") # TODO: avoid overriding patient id parameter for n in neoantigens: if n.patient_identifier is None: n.patient_identifier = patient_id # validates input data self.neoantigens = [ModelValidator.validate_neoantigen(n) for n in neoantigens] self.patients = {patient.identifier: ModelValidator.validate_patient(patient) for patient in patients} self._validate_input_data() logger.info("Data loaded") def _initialise_logs(self, output_prefix, work_folder): if work_folder and os.path.exists(work_folder): logfile = os.path.join(work_folder, "{}.log".format(output_prefix)) else: logfile = os.environ.get(NEOFOX_LOG_FILE_ENV) if logfile is not None: logzero.logfile(logfile) # TODO: this does not work logzero.loglevel(logging.DEBUG) logger.info("Loading data...") def _validate_input_data(self): patient_identifiers_from_neoantigens = set([n.patient_identifier for n in self.neoantigens]) patient_identifiers_from_patients = set([p.identifier for p in self.patients.values()]) # check that there are no repeated neoantigens neoantigen_identifiers = [n.identifier for n in self.neoantigens] if len(neoantigen_identifiers) != len(set(neoantigen_identifiers)): raise NeofoxDataValidationException("There are repeated neoantigens!") # checks that no neoantigen is referring to an empty patient if "" in patient_identifiers_from_neoantigens or None in patient_identifiers_from_neoantigens: raise NeofoxDataValidationException( "There are neoantigens missing a reference to a patient") # checks that there is no neoantigen referring to a non existing patient missing_patient_identifiers = patient_identifiers_from_neoantigens.difference(patient_identifiers_from_patients) if len(missing_patient_identifiers) > 0: raise NeofoxDataValidationException( "There are neoantigens referring to missing patients: {}".format(missing_patient_identifiers))
[docs] def get_annotations(self) -> List[NeoantigenAnnotations]: """ Loads epitope data (if file has been not imported to R; colnames need to be changed), adds data to class that are needed to calculate, calls epitope class --> determination of epitope properties, write to txt file """ logger.info("Starting NeoFox annotations...") # feature calculation for each epitope futures = [] start = time.time() for neoantigen in self.neoantigens: patient = self.patients.get(neoantigen.patient_identifier) logger.debug("Neoantigen: {}".format(neoantigen.to_json(indent=3))) logger.debug("Patient: {}".format(patient.to_json(indent=3))) futures.append(self.dask_client.submit( NeoFox.annotate_neoantigen, neoantigen, patient, self.reference_folder, self.configuration)) annotations = self.dask_client.gather(futures) end = time.time() logger.info("Elapsed time for annotating {} neoantigens {} seconds".format( len(self.neoantigens), int(end - start))) return annotations
[docs] @staticmethod def annotate_neoantigen(neoantigen: Neoantigen, patient: Patient, reference_folder: ReferenceFolder, configuration: DependenciesConfiguration): logger.info("Starting neoantigen annotation: {}".format(neoantigen.identifier)) start = time.time() annotation = NeoantigenAnnotator(reference_folder, configuration).get_annotation(neoantigen, patient) end = time.time() logger.info("Elapsed time for annotating neoantigen {}: {} seconds".format( neoantigen.identifier, int(end - start))) return annotation
html/_modules/neofox/annotator.html0000664000175000017500000011466313743770171017753 0ustar priesgopriesgo neofox.annotator — Neofox 0.4.0.dev1 documentation

Source code for neofox.annotator

#!/usr/bin/env python
#
# Copyright (c) 2020-2030 Translational Oncology at the Medical Center of the Johannes Gutenberg-University Mainz gGmbH.
#
# This file is part of Neofox
# (see https://github.com/tron-bioinformatics/neofox).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.#

from logzero import logger
from datetime import datetime
import neofox
from neofox.annotation_resources.uniprot.uniprot import Uniprot
from neofox.helpers.epitope_helper import EpitopeHelper
from neofox.helpers.runner import Runner
from neofox.MHC_predictors.MixMHCpred.mixmhc2pred import MixMhc2Pred
from neofox.MHC_predictors.MixMHCpred.mixmhcpred import MixMHCpred
from neofox.MHC_predictors.netmhcpan.combine_netmhcIIpan_pred_multiple_binders import BestAndMultipleBinderMhcII
from neofox.MHC_predictors.netmhcpan.combine_netmhcpan_pred_multiple_binders import BestAndMultipleBinder
from neofox.published_features.differential_binding.amplitude import Amplitude
from neofox.published_features.differential_binding.differential_binding import DifferentialBinding
from neofox.published_features.Tcell_predictor.tcellpredictor_wrapper import TcellPrediction
from neofox.published_features.dissimilarity_garnish.dissimilaritycalculator import DissimilarityCalculator
from neofox.published_features.neoag.neoag_gbm_model import NeoagCalculator
from neofox.published_features.neoantigen_fitness.neoantigen_fitness import NeoantigenFitnessCalculator
from neofox.published_features.self_similarity.self_similarity import SelfSimilarityCalculator
from neofox.published_features.vaxrank import vaxrank
from neofox.published_features.iedb_immunogenicity.iedb import IEDBimmunogenicity
from neofox.published_features.expression import Expression
from neofox.published_features.priority_score import PriorityScore
from neofox.model.neoantigen import Patient, Neoantigen, NeoantigenAnnotations
from neofox.references.references import ReferenceFolder, DependenciesConfiguration


[docs]class NeoantigenAnnotator: def __init__(self, references: ReferenceFolder, configuration: DependenciesConfiguration): """class to annotate neoantigens""" runner = Runner() self.dissimilarity_calculator = DissimilarityCalculator( runner=runner, configuration=configuration, proteome_db=references.proteome_db) self.neoantigen_fitness_calculator = NeoantigenFitnessCalculator( runner=runner, configuration=configuration, iedb=references.iedb) self.neoag_calculator = NeoagCalculator(runner=runner, configuration=configuration) self.netmhc2pan = BestAndMultipleBinderMhcII(runner=runner, configuration=configuration) self.mixmhc2 = MixMhc2Pred(runner=runner, configuration=configuration) self.netmhcpan = BestAndMultipleBinder(runner=runner, configuration=configuration) self.mixmhc = MixMHCpred(runner=runner, configuration=configuration) self.available_alleles = references.get_available_alleles() self.uniprot = Uniprot(references.uniprot) self.tcell_predictor = TcellPrediction() self.self_similarity = SelfSimilarityCalculator() # NOTE: these resources do not read any file thus can be initialised fast self.differential_binding = DifferentialBinding() self.priority_score_calculator = PriorityScore() self.iedb_immunogenicity = IEDBimmunogenicity() self.differential_binding = DifferentialBinding() self.amplitude = Amplitude()
[docs] def get_annotation(self, neoantigen: Neoantigen, patient: Patient) -> NeoantigenAnnotations: """Calculate new epitope features and add to dictonary that stores all properties""" self._initialise_annotations(neoantigen) # decides which VAF to use vaf_rna = neoantigen.rna_variant_allele_frequency if not patient.is_rna_available: logger.warning("Using the DNA VAF to estimate the RNA VAF as the patient does not have RNA available") # TODO: overwrite value in the neoantigen object vaf_rna = neoantigen.dna_variant_allele_frequency # TODO: this is needed by the T cell predictor, move this construction inside by passing the neoantigen substitution = "{}{}{}".format( neoantigen.mutation.wild_type_aminoacid, neoantigen.mutation.position, neoantigen.mutation.mutated_aminoacid) # MHC binding independent features expression_calculator = Expression( transcript_expression=neoantigen.rna_expression, vaf_rna=vaf_rna) self.annotations.annotations.extend(expression_calculator.get_annotations()) sequence_not_in_uniprot = self.uniprot.is_sequence_not_in_uniprot(neoantigen.mutation.mutated_xmer) self.annotations.annotations.extend(self.uniprot.get_annotations(sequence_not_in_uniprot)) # HLA I predictions: NetMHCpan self.netmhcpan.run( sequence_mut=neoantigen.mutation.mutated_xmer, sequence_wt=neoantigen.mutation.wild_type_xmer, mhc=patient.mhc1, available_mhc_alleles=self.available_alleles.get_available_mhc_i()) self.annotations.annotations.extend(self.netmhcpan.get_annotations()) # HLA II predictions: NetMHCIIpan self.netmhc2pan.run( sequence=neoantigen.mutation.mutated_xmer, sequence_reference=neoantigen.mutation.wild_type_xmer, mhc=patient.mhc2, available_mhc=self.available_alleles.get_available_mhc_ii()) self.annotations.annotations.extend(self.netmhc2pan.get_annotations()) # Amplitude self.amplitude.run(netmhcpan=self.netmhcpan, netmhc2pan=self.netmhc2pan) self.annotations.annotations.extend(self.amplitude.get_annotations()) # Neoantigen fitness self.annotations.annotations.extend( self.neoantigen_fitness_calculator.get_annotations(self.netmhcpan, self.amplitude)) # Differential Binding self.annotations.annotations.extend(self.differential_binding.get_annotations_dai(self.netmhcpan)) self.annotations.annotations.extend(self.differential_binding.get_annotations(self.netmhcpan, self.amplitude)) self.annotations.annotations.extend( self.differential_binding.get_annotations_mhc2(self.netmhc2pan, self.amplitude)) # T cell predictor self.annotations.annotations.extend(self.tcell_predictor.get_annotations( gene=neoantigen.transcript.gene, substitution=substitution, netmhcpan=self.netmhcpan)) # self-similarity self.annotations.annotations.extend(self.self_similarity.get_annnotations( netmhcpan=self.netmhcpan)) # number of mismatches and priority score self.annotations.annotations.extend(self.priority_score_calculator.get_annotations( netmhcpan=self.netmhcpan, vaf_transcr=vaf_rna, vaf_tum=neoantigen.dna_variant_allele_frequency, expr=neoantigen.rna_expression, mut_not_in_prot=sequence_not_in_uniprot)) # neoag immunogenicity model peptide_variant_position = EpitopeHelper.position_of_mutation_epitope( wild_type=self.netmhcpan.best4_affinity_epitope_WT, mutation=self.netmhcpan.best4_affinity_epitope) self.annotations.annotations.append(self.neoag_calculator.get_annotation( sample_id=patient.identifier, netmhcpan=self.netmhcpan, peptide_variant_position=peptide_variant_position)) # IEDB immunogenicity self.annotations.annotations.extend(self.iedb_immunogenicity.get_annotations( netmhcpan=self.netmhcpan, mhci_allele=self.netmhcpan.best4_affinity_allele)) # MixMHCpred self.mixmhc.run( sequence_wt=neoantigen.mutation.wild_type_xmer, sequence_mut=neoantigen.mutation.mutated_xmer, mhc=patient.mhc1) self.annotations.annotations.extend(self.mixmhc.get_annotations()) # MixMHC2pred self.mixmhc2.run( mhc=patient.mhc2, sequence_wt=neoantigen.mutation.wild_type_xmer, sequence_mut=neoantigen.mutation.mutated_xmer) self.annotations.annotations.extend(self.mixmhc2.get_annotations()) # dissimilarity to self-proteome self.annotations.annotations.extend(self.dissimilarity_calculator.get_annotations( netmhcpan=self.netmhcpan)) # vaxrank vaxrankscore = vaxrank.VaxRank() vaxrankscore.run(mutation_scores=self.netmhcpan.epitope_affinities, expression_score=expression_calculator.expression) self.annotations.annotations.extend(vaxrankscore.get_annotations()) return self.annotations
def _initialise_annotations(self, neoantigen): self.annotations = NeoantigenAnnotations() self.annotations.neoantigen_identifier = neoantigen.identifier self.annotations.annotator = "Neofox" self.annotations.annotator_version = neofox.VERSION self.annotations.timestamp = "{:%Y%m%d%H%M%S%f}".format(datetime.now()) # TODO: set the hash fro the resources self.annotations.annotations = []
html/_modules/neofox/exceptions.html0000664000175000017500000001754213743770171020125 0ustar priesgopriesgo neofox.exceptions — Neofox 0.4.0.dev1 documentation

Source code for neofox.exceptions

#
# Copyright (c) 2020-2030 Translational Oncology at the Medical Center of the Johannes Gutenberg-University Mainz gGmbH.
#
# This file is part of Neofox
# (see https://github.com/tron-bioinformatics/neofox).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.#
[docs]class NeofoxInputParametersException(ValueError): pass
[docs]class NeofoxConfigurationException(ValueError): pass
[docs]class NeofoxCommandException(ValueError): pass
[docs]class NeofoxReferenceException(ValueError): pass
[docs]class NeofoxDataValidationException(ValueError): pass
html/_modules/betterproto.html0000664000175000017500000053414413743770170017020 0ustar priesgopriesgo betterproto — Neofox 0.4.0.dev1 documentation

Source code for betterproto

#
# Copyright (c) 2020-2030 Translational Oncology at the Medical Center of the Johannes Gutenberg-University Mainz gGmbH.
#
# This file is part of Neofox
# (see https://github.com/tron-bioinformatics/neofox).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.#
import dataclasses
import enum
import inspect
import json
import struct
import sys
from abc import ABC
from base64 import b64encode, b64decode
from datetime import datetime, timedelta, timezone
from typing import (
    Any,
    AsyncGenerator,
    Callable,
    Collection,
    Dict,
    Generator,
    Iterable,
    List,
    Mapping,
    Optional,
    SupportsBytes,
    Tuple,
    Type,
    TypeVar,
    Union,
    get_type_hints,
    TYPE_CHECKING,
)


import grpclib.const
import stringcase

from .casing import safe_snake_case

if TYPE_CHECKING:
    from grpclib._protocols import IProtoMessage
    from grpclib.client import Channel
    from grpclib.metadata import Deadline

if not (sys.version_info.major == 3 and sys.version_info.minor >= 7):
    # Apply backport of datetime.fromisoformat from 3.7
    from backports.datetime_fromisoformat import MonkeyPatch

    MonkeyPatch.patch_fromisoformat()


# Proto 3 data types
TYPE_ENUM = "enum"
TYPE_BOOL = "bool"
TYPE_INT32 = "int32"
TYPE_INT64 = "int64"
TYPE_UINT32 = "uint32"
TYPE_UINT64 = "uint64"
TYPE_SINT32 = "sint32"
TYPE_SINT64 = "sint64"
TYPE_FLOAT = "float"
TYPE_DOUBLE = "double"
TYPE_FIXED32 = "fixed32"
TYPE_SFIXED32 = "sfixed32"
TYPE_FIXED64 = "fixed64"
TYPE_SFIXED64 = "sfixed64"
TYPE_STRING = "string"
TYPE_BYTES = "bytes"
TYPE_MESSAGE = "message"
TYPE_MAP = "map"


# Fields that use a fixed amount of space (4 or 8 bytes)
FIXED_TYPES = [
    TYPE_FLOAT,
    TYPE_DOUBLE,
    TYPE_FIXED32,
    TYPE_SFIXED32,
    TYPE_FIXED64,
    TYPE_SFIXED64,
]

# Fields that are numerical 64-bit types
INT_64_TYPES = [TYPE_INT64, TYPE_UINT64, TYPE_SINT64, TYPE_FIXED64, TYPE_SFIXED64]

# Fields that are efficiently packed when
PACKED_TYPES = [
    TYPE_ENUM,
    TYPE_BOOL,
    TYPE_INT32,
    TYPE_INT64,
    TYPE_UINT32,
    TYPE_UINT64,
    TYPE_SINT32,
    TYPE_SINT64,
    TYPE_FLOAT,
    TYPE_DOUBLE,
    TYPE_FIXED32,
    TYPE_SFIXED32,
    TYPE_FIXED64,
    TYPE_SFIXED64,
]

# Wire types
# https://developers.google.com/protocol-buffers/docs/encoding#structure
WIRE_VARINT = 0
WIRE_FIXED_64 = 1
WIRE_LEN_DELIM = 2
WIRE_FIXED_32 = 5

# Mappings of which Proto 3 types correspond to which wire types.
WIRE_VARINT_TYPES = [
    TYPE_ENUM,
    TYPE_BOOL,
    TYPE_INT32,
    TYPE_INT64,
    TYPE_UINT32,
    TYPE_UINT64,
    TYPE_SINT32,
    TYPE_SINT64,
]

WIRE_FIXED_32_TYPES = [TYPE_FLOAT, TYPE_FIXED32, TYPE_SFIXED32]
WIRE_FIXED_64_TYPES = [TYPE_DOUBLE, TYPE_FIXED64, TYPE_SFIXED64]
WIRE_LEN_DELIM_TYPES = [TYPE_STRING, TYPE_BYTES, TYPE_MESSAGE, TYPE_MAP]


# Protobuf datetimes start at the Unix Epoch in 1970 in UTC.
def datetime_default_gen():
    return datetime(1970, 1, 1, tzinfo=timezone.utc)


DATETIME_ZERO = datetime_default_gen()


class Casing(enum.Enum):
    """Casing constants for serialization."""

    CAMEL = stringcase.camelcase
    SNAKE = stringcase.snakecase


class _PLACEHOLDER:
    pass


PLACEHOLDER: Any = _PLACEHOLDER()


@dataclasses.dataclass(frozen=True)
class FieldMetadata:
    """Stores internal metadata used for parsing & serialization."""

    # Protobuf field number
    number: int
    # Protobuf type name
    proto_type: str
    # Map information if the proto_type is a map
    map_types: Optional[Tuple[str, str]] = None
    # Groups several "one-of" fields together
    group: Optional[str] = None
    # Describes the wrapped type (e.g. when using google.protobuf.BoolValue)
    wraps: Optional[str] = None

    @staticmethod
    def get(field: dataclasses.Field) -> "FieldMetadata":
        """Returns the field metadata for a dataclass field."""
        return field.metadata["betterproto"]


def dataclass_field(
    number: int,
    proto_type: str,
    *,
    map_types: Optional[Tuple[str, str]] = None,
    group: Optional[str] = None,
    wraps: Optional[str] = None,
) -> dataclasses.Field:
    """Creates a dataclass field with attached protobuf metadata."""
    return dataclasses.field(
        default=PLACEHOLDER,
        metadata={
            "betterproto": FieldMetadata(number, proto_type, map_types, group, wraps)
        },
    )


# Note: the fields below return `Any` to prevent type errors in the generated
# data classes since the types won't match with `Field` and they get swapped
# out at runtime. The generated dataclass variables are still typed correctly.


def enum_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_ENUM, group=group)


def bool_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_BOOL, group=group)


def int32_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_INT32, group=group)


def int64_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_INT64, group=group)


def uint32_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_UINT32, group=group)


def uint64_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_UINT64, group=group)


def sint32_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_SINT32, group=group)


def sint64_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_SINT64, group=group)


def float_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_FLOAT, group=group)


def double_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_DOUBLE, group=group)


def fixed32_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_FIXED32, group=group)


def fixed64_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_FIXED64, group=group)


def sfixed32_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_SFIXED32, group=group)


def sfixed64_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_SFIXED64, group=group)


def string_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_STRING, group=group)


def bytes_field(number: int, group: Optional[str] = None) -> Any:
    return dataclass_field(number, TYPE_BYTES, group=group)


def message_field(
    number: int, group: Optional[str] = None, wraps: Optional[str] = None
) -> Any:
    return dataclass_field(number, TYPE_MESSAGE, group=group, wraps=wraps)


def map_field(
    number: int, key_type: str, value_type: str, group: Optional[str] = None
) -> Any:
    return dataclass_field(
        number, TYPE_MAP, map_types=(key_type, value_type), group=group
    )


class Enum(int, enum.Enum):
    """Protocol buffers enumeration base class. Acts like `enum.IntEnum`."""

    @classmethod
    def from_string(cls, name: str) -> int:
        """Return the value which corresponds to the string name."""
        try:
            return cls.__members__[name]
        except KeyError as e:
            raise ValueError(f"Unknown value {name} for enum {cls.__name__}") from e


def _pack_fmt(proto_type: str) -> str:
    """Returns a little-endian format string for reading/writing binary."""
    return {
        TYPE_DOUBLE: "<d",
        TYPE_FLOAT: "<f",
        TYPE_FIXED32: "<I",
        TYPE_FIXED64: "<Q",
        TYPE_SFIXED32: "<i",
        TYPE_SFIXED64: "<q",
    }[proto_type]


def encode_varint(value: int) -> bytes:
    """Encodes a single varint value for serialization."""
    b: List[int] = []

    if value < 0:
        value += 1 << 64

    bits = value & 0x7F
    value >>= 7
    while value:
        b.append(0x80 | bits)
        bits = value & 0x7F
        value >>= 7
    return bytes(b + [bits])


def _preprocess_single(proto_type: str, wraps: str, value: Any) -> bytes:
    """Adjusts values before serialization."""
    if proto_type in [
        TYPE_ENUM,
        TYPE_BOOL,
        TYPE_INT32,
        TYPE_INT64,
        TYPE_UINT32,
        TYPE_UINT64,
    ]:
        return encode_varint(value)
    elif proto_type in [TYPE_SINT32, TYPE_SINT64]:
        # Handle zig-zag encoding.
        if value >= 0:
            value = value << 1
        else:
            value = (value << 1) ^ (~0)
        return encode_varint(value)
    elif proto_type in FIXED_TYPES:
        return struct.pack(_pack_fmt(proto_type), value)
    elif proto_type == TYPE_STRING:
        return value.encode("utf-8")
    elif proto_type == TYPE_MESSAGE:
        if isinstance(value, datetime):
            # Convert the `datetime` to a timestamp message.
            seconds = int(value.timestamp())
            nanos = int(value.microsecond * 1e3)
            value = _Timestamp(seconds=seconds, nanos=nanos)
        elif isinstance(value, timedelta):
            # Convert the `timedelta` to a duration message.
            total_ms = value // timedelta(microseconds=1)
            seconds = int(total_ms / 1e6)
            nanos = int((total_ms % 1e6) * 1e3)
            value = _Duration(seconds=seconds, nanos=nanos)
        elif wraps:
            if value is None:
                return b""
            value = _get_wrapper(wraps)(value=value)

        return bytes(value)

    return value


def _serialize_single(
    field_number: int,
    proto_type: str,
    value: Any,
    *,
    serialize_empty: bool = False,
    wraps: str = "",
) -> bytes:
    """Serializes a single field and value."""
    value = _preprocess_single(proto_type, wraps, value)

    output = b""
    if proto_type in WIRE_VARINT_TYPES:
        key = encode_varint(field_number << 3)
        output += key + value
    elif proto_type in WIRE_FIXED_32_TYPES:
        key = encode_varint((field_number << 3) | 5)
        output += key + value
    elif proto_type in WIRE_FIXED_64_TYPES:
        key = encode_varint((field_number << 3) | 1)
        output += key + value
    elif proto_type in WIRE_LEN_DELIM_TYPES:
        if len(value) or serialize_empty or wraps:
            key = encode_varint((field_number << 3) | 2)
            output += key + encode_varint(len(value)) + value
    else:
        raise NotImplementedError(proto_type)

    return output


def decode_varint(buffer: bytes, pos: int, signed: bool = False) -> Tuple[int, int]:
    """
    Decode a single varint value from a byte buffer. Returns the value and the
    new position in the buffer.
    """
    result = 0
    shift = 0
    while 1:
        b = buffer[pos]
        result |= (b & 0x7F) << shift
        pos += 1
        if not (b & 0x80):
            return (result, pos)
        shift += 7
        if shift >= 64:
            raise ValueError("Too many bytes when decoding varint.")


@dataclasses.dataclass(frozen=True)
class ParsedField:
    number: int
    wire_type: int
    value: Any
    raw: bytes


def parse_fields(value: bytes) -> Generator[ParsedField, None, None]:
    i = 0
    while i < len(value):
        start = i
        num_wire, i = decode_varint(value, i)
        number = num_wire >> 3
        wire_type = num_wire & 0x7

        decoded: Any = None
        if wire_type == 0:
            decoded, i = decode_varint(value, i)
        elif wire_type == 1:
            decoded, i = value[i : i + 8], i + 8
        elif wire_type == 2:
            length, i = decode_varint(value, i)
            decoded = value[i : i + length]
            i += length
        elif wire_type == 5:
            decoded, i = value[i : i + 4], i + 4

        yield ParsedField(
            number=number, wire_type=wire_type, value=decoded, raw=value[start:i]
        )


# Bound type variable to allow methods to return `self` of subclasses
T = TypeVar("T", bound="Message")


class ProtoClassMetadata:
    cls: Type["Message"]

    def __init__(self, cls: Type["Message"]):
        self.cls = cls
        by_field = {}
        by_group = {}

        for field in dataclasses.fields(cls):
            meta = FieldMetadata.get(field)

            if meta.group:
                # This is part of a one-of group.
                by_field[field.name] = meta.group

                by_group.setdefault(meta.group, set()).add(field)

        self.oneof_group_by_field = by_field
        self.oneof_field_by_group = by_group

        self.init_default_gen()
        self.init_cls_by_field()

    def init_default_gen(self):
        default_gen = {}

        for field in dataclasses.fields(self.cls):
            meta = FieldMetadata.get(field)
            default_gen[field.name] = self.cls._get_field_default_gen(field, meta)

        self.default_gen = default_gen

    def init_cls_by_field(self):
        field_cls = {}

        for field in dataclasses.fields(self.cls):
            meta = FieldMetadata.get(field)
            if meta.proto_type == TYPE_MAP:
                assert meta.map_types
                kt = self.cls._cls_for(field, index=0)
                vt = self.cls._cls_for(field, index=1)
                Entry = dataclasses.make_dataclass(
                    "Entry",
                    [
                        ("key", kt, dataclass_field(1, meta.map_types[0])),
                        ("value", vt, dataclass_field(2, meta.map_types[1])),
                    ],
                    bases=(Message,),
                )
                field_cls[field.name] = Entry
                field_cls[field.name + ".value"] = vt
            else:
                field_cls[field.name] = self.cls._cls_for(field)

        self.cls_by_field = field_cls


class Message(ABC):
    """
    A protobuf message base class. Generated code will inherit from this and
    register the message fields which get used by the serializers and parsers
    to go between Python, binary and JSON protobuf message representations.
    """

    _serialized_on_wire: bool
    _unknown_fields: bytes
    _group_map: Dict[str, dict]

    def __post_init__(self) -> None:
        # Keep track of whether every field was default
        all_sentinel = True

        # Set a default value for each field in the class after `__init__` has
        # already been run.
        group_map: Dict[str, dataclasses.Field] = {}
        for field in dataclasses.fields(self):
            meta = FieldMetadata.get(field)

            if meta.group:
                group_map.setdefault(meta.group)

            if getattr(self, field.name) != PLACEHOLDER:
                # Skip anything not set to the sentinel value
                all_sentinel = False

                if meta.group:
                    # This was set, so make it the selected value of the one-of.
                    group_map[meta.group] = field

                continue

            setattr(self, field.name, self._get_field_default(field, meta))

        # Now that all the defaults are set, reset it!
        self.__dict__["_serialized_on_wire"] = not all_sentinel
        self.__dict__["_unknown_fields"] = b""
        self.__dict__["_group_map"] = group_map

    def __setattr__(self, attr: str, value: Any) -> None:
        if attr != "_serialized_on_wire":
            # Track when a field has been set.
            self.__dict__["_serialized_on_wire"] = True

        if hasattr(self, "_group_map"):  # __post_init__ had already run
            if attr in self._betterproto.oneof_group_by_field:
                group = self._betterproto.oneof_group_by_field[attr]
                for field in self._betterproto.oneof_field_by_group[group]:
                    if field.name == attr:
                        self._group_map[group] = field
                    else:
                        super().__setattr__(
                            field.name,
                            self._get_field_default(field, FieldMetadata.get(field)),
                        )

        super().__setattr__(attr, value)

    @property
    def _betterproto(self):
        """
        Lazy initialize metadata for each protobuf class.
        It may be initialized multiple times in a multi-threaded environment,
        but that won't affect the correctness.
        """
        meta = getattr(self.__class__, "_betterproto_meta", None)
        if not meta:
            meta = ProtoClassMetadata(self.__class__)
            self.__class__._betterproto_meta = meta
        return meta

    def __bytes__(self) -> bytes:
        """
        Get the binary encoded Protobuf representation of this instance.
        """
        output = b""
        for field in dataclasses.fields(self):
            meta = FieldMetadata.get(field)
            value = getattr(self, field.name)

            if value is None:
                # Optional items should be skipped. This is used for the Google
                # wrapper types.
                continue

            # Being selected in a a group means this field is the one that is
            # currently set in a `oneof` group, so it must be serialized even
            # if the value is the default zero value.
            selected_in_group = False
            if meta.group and self._group_map[meta.group] == field:
                selected_in_group = True

            serialize_empty = False
            if isinstance(value, Message) and value._serialized_on_wire:
                # Empty messages can still be sent on the wire if they were
                # set (or received empty).
                serialize_empty = True

            if value == self._get_field_default(field, meta) and not (
                selected_in_group or serialize_empty
            ):
                # Default (zero) values are not serialized. Two exceptions are
                # if this is the selected oneof item or if we know we have to
                # serialize an empty message (i.e. zero value was explicitly
                # set by the user).
                continue

            if isinstance(value, list):
                if meta.proto_type in PACKED_TYPES:
                    # Packed lists look like a length-delimited field. First,
                    # preprocess/encode each value into a buffer and then
                    # treat it like a field of raw bytes.
                    buf = b""
                    for item in value:
                        buf += _preprocess_single(meta.proto_type, "", item)
                    output += _serialize_single(meta.number, TYPE_BYTES, buf)
                else:
                    for item in value:
                        output += _serialize_single(
                            meta.number, meta.proto_type, item, wraps=meta.wraps or ""
                        )
            elif isinstance(value, dict):
                for k, v in value.items():
                    assert meta.map_types
                    sk = _serialize_single(1, meta.map_types[0], k)
                    sv = _serialize_single(2, meta.map_types[1], v)
                    output += _serialize_single(meta.number, meta.proto_type, sk + sv)
            else:
                output += _serialize_single(
                    meta.number,
                    meta.proto_type,
                    value,
                    serialize_empty=serialize_empty,
                    wraps=meta.wraps or "",
                )

        return output + self._unknown_fields

    # For compatibility with other libraries
    SerializeToString = __bytes__

    @classmethod
    def _type_hint(cls, field_name: str) -> Type:
        module = inspect.getmodule(cls)
        type_hints = get_type_hints(cls, vars(module))
        return type_hints[field_name]

    @classmethod
    def _cls_for(cls, field: dataclasses.Field, index: int = 0) -> Type:
        """Get the message class for a field from the type hints."""
        field_cls = cls._type_hint(field.name)
        if hasattr(field_cls, "__args__") and index >= 0:
            field_cls = field_cls.__args__[index]
        return field_cls

    def _get_field_default(self, field: dataclasses.Field, meta: FieldMetadata) -> Any:
        return self._betterproto.default_gen[field.name]()

    @classmethod
    def _get_field_default_gen(
        cls, field: dataclasses.Field, meta: FieldMetadata
    ) -> Any:
        t = cls._type_hint(field.name)

        if hasattr(t, "__origin__"):
            if t.__origin__ in (dict, Dict):
                # This is some kind of map (dict in Python).
                return dict
            elif t.__origin__ in (list, List):
                # This is some kind of list (repeated) field.
                return list
            elif t.__origin__ == Union and t.__args__[1] == type(None):
                # This is an optional (wrapped) field. For setting the default we
                # really don't care what kind of field it is.
                return type(None)
            else:
                return t
        elif issubclass(t, Enum):
            # Enums always default to zero.
            return int
        elif t == datetime:
            # Offsets are relative to 1970-01-01T00:00:00Z
            return datetime_default_gen
        else:
            # This is either a primitive scalar or another message type. Calling
            # it should result in its zero value.
            return t

    def _postprocess_single(
        self, wire_type: int, meta: FieldMetadata, field: dataclasses.Field, value: Any
    ) -> Any:
        """Adjusts values after parsing."""
        if wire_type == WIRE_VARINT:
            if meta.proto_type in [TYPE_INT32, TYPE_INT64]:
                bits = int(meta.proto_type[3:])
                value = value & ((1 << bits) - 1)
                signbit = 1 << (bits - 1)
                value = int((value ^ signbit) - signbit)
            elif meta.proto_type in [TYPE_SINT32, TYPE_SINT64]:
                # Undo zig-zag encoding
                value = (value >> 1) ^ (-(value & 1))
            elif meta.proto_type == TYPE_BOOL:
                # Booleans use a varint encoding, so convert it to true/false.
                value = value > 0
        elif wire_type in [WIRE_FIXED_32, WIRE_FIXED_64]:
            fmt = _pack_fmt(meta.proto_type)
            value = struct.unpack(fmt, value)[0]
        elif wire_type == WIRE_LEN_DELIM:
            if meta.proto_type == TYPE_STRING:
                value = value.decode("utf-8")
            elif meta.proto_type == TYPE_MESSAGE:
                cls = self._betterproto.cls_by_field[field.name]

                if cls == datetime:
                    value = _Timestamp().parse(value).to_datetime()
                elif cls == timedelta:
                    value = _Duration().parse(value).to_timedelta()
                elif meta.wraps:
                    # This is a Google wrapper value message around a single
                    # scalar type.
                    value = _get_wrapper(meta.wraps)().parse(value).value
                else:
                    value = cls().parse(value)
                    value._serialized_on_wire = True
            elif meta.proto_type == TYPE_MAP:
                value = self._betterproto.cls_by_field[field.name]().parse(value)

        return value

    def parse(self: T, data: bytes) -> T:
        """
        Parse the binary encoded Protobuf into this message instance. This
        returns the instance itself and is therefore assignable and chainable.
        """
        fields = {f.metadata["betterproto"].number: f for f in dataclasses.fields(self)}
        for parsed in parse_fields(data):
            if parsed.number in fields:
                field = fields[parsed.number]
                meta = FieldMetadata.get(field)

                value: Any
                if (
                    parsed.wire_type == WIRE_LEN_DELIM
                    and meta.proto_type in PACKED_TYPES
                ):
                    # This is a packed repeated field.
                    pos = 0
                    value = []
                    while pos < len(parsed.value):
                        if meta.proto_type in ["float", "fixed32", "sfixed32"]:
                            decoded, pos = parsed.value[pos : pos + 4], pos + 4
                            wire_type = WIRE_FIXED_32
                        elif meta.proto_type in ["double", "fixed64", "sfixed64"]:
                            decoded, pos = parsed.value[pos : pos + 8], pos + 8
                            wire_type = WIRE_FIXED_64
                        else:
                            decoded, pos = decode_varint(parsed.value, pos)
                            wire_type = WIRE_VARINT
                        decoded = self._postprocess_single(
                            wire_type, meta, field, decoded
                        )
                        value.append(decoded)
                else:
                    value = self._postprocess_single(
                        parsed.wire_type, meta, field, parsed.value
                    )

                current = getattr(self, field.name)
                if meta.proto_type == TYPE_MAP:
                    # Value represents a single key/value pair entry in the map.
                    current[value.key] = value.value
                elif isinstance(current, list) and not isinstance(value, list):
                    current.append(value)
                else:
                    setattr(self, field.name, value)
            else:
                self._unknown_fields += parsed.raw

        return self

    # For compatibility with other libraries.
    @classmethod
    def FromString(cls: Type[T], data: bytes) -> T:
        return cls().parse(data)

    def to_dict(
        self, casing: Casing = Casing.CAMEL, include_default_values: bool = False
    ) -> dict:
        """
        Returns a dict representation of this message instance which can be
        used to serialize to e.g. JSON. Defaults to camel casing for
        compatibility but can be set to other modes.

        `include_default_values` can be set to `True` to include default
        values of fields. E.g. an `int32` type field with `0` value will
        not be in returned dict if `include_default_values` is set to
        `False`.
        """
        output: Dict[str, Any] = {}
        for field in dataclasses.fields(self):
            meta = FieldMetadata.get(field)
            v = getattr(self, field.name)
            cased_name = casing(field.name).rstrip("_")  # type: ignore
            if meta.proto_type == "message":
                if isinstance(v, datetime):
                    if v != DATETIME_ZERO or include_default_values:
                        output[cased_name] = _Timestamp.timestamp_to_json(v)
                elif isinstance(v, timedelta):
                    if v != timedelta(0) or include_default_values:
                        output[cased_name] = _Duration.delta_to_json(v)
                elif meta.wraps:
                    if v is not None or include_default_values:
                        output[cased_name] = v
                elif isinstance(v, list):
                    # Convert each item.
                    v = [i.to_dict(casing, include_default_values) for i in v]
                    if v or include_default_values:
                        output[cased_name] = v
                else:
                    if v._serialized_on_wire or include_default_values:
                        output[cased_name] = v.to_dict(casing, include_default_values)
            elif meta.proto_type == "map":
                for k in v:
                    if hasattr(v[k], "to_dict"):
                        v[k] = v[k].to_dict(casing, include_default_values)

                if v or include_default_values:
                    output[cased_name] = v
            elif v != self._get_field_default(field, meta) or include_default_values:
                if meta.proto_type in INT_64_TYPES:
                    if isinstance(v, list):
                        output[cased_name] = [str(n) for n in v]
                    else:
                        output[cased_name] = str(v)
                elif meta.proto_type == TYPE_BYTES:
                    if isinstance(v, list):
                        output[cased_name] = [b64encode(b).decode("utf8") for b in v]
                    else:
                        output[cased_name] = b64encode(v).decode("utf8")
                elif meta.proto_type == TYPE_ENUM:
                    enum_values = list(
                        self._betterproto.cls_by_field[field.name]
                    )  # type: ignore
                    if isinstance(v, list):
                        output[cased_name] = [enum_values[e].name for e in v]
                    else:
                        output[cased_name] = enum_values[v].name
                else:
                    output[cased_name] = v
        return output

    def from_dict(self: T, value: dict) -> T:
        """
        Parse the key/value pairs in `value` into this message instance. This
        returns the instance itself and is therefore assignable and chainable.
        """
        self._serialized_on_wire = True
        fields_by_name = {f.name: f for f in dataclasses.fields(self)}
        for key in value:
            snake_cased = safe_snake_case(key)
            if snake_cased in fields_by_name:
                field = fields_by_name[snake_cased]
                meta = FieldMetadata.get(field)

                if value[key] is not None:
                    if meta.proto_type == "message":
                        v = getattr(self, field.name)
                        if isinstance(v, list):
                            cls = self._betterproto.cls_by_field[field.name]
                            for i in range(len(value[key])):
                                v.append(cls().from_dict(value[key][i]))
                        elif isinstance(v, datetime):
                            v = datetime.fromisoformat(
                                value[key].replace("Z", "+00:00")
                            )
                            setattr(self, field.name, v)
                        elif isinstance(v, timedelta):
                            v = timedelta(seconds=float(value[key][:-1]))
                            setattr(self, field.name, v)
                        elif meta.wraps:
                            setattr(self, field.name, value[key])
                        else:
                            v.from_dict(value[key])
                    elif meta.map_types and meta.map_types[1] == TYPE_MESSAGE:
                        v = getattr(self, field.name)
                        cls = self._betterproto.cls_by_field[field.name + ".value"]
                        for k in value[key]:
                            v[k] = cls().from_dict(value[key][k])
                    else:
                        v = value[key]
                        if meta.proto_type in INT_64_TYPES:
                            if isinstance(value[key], list):
                                v = [int(n) for n in value[key]]
                            else:
                                v = int(value[key])
                        elif meta.proto_type == TYPE_BYTES:
                            if isinstance(value[key], list):
                                v = [b64decode(n) for n in value[key]]
                            else:
                                v = b64decode(value[key])
                        elif meta.proto_type == TYPE_ENUM:
                            enum_cls = self._betterproto.cls_by_field[field.name]
                            if isinstance(v, list):
                                v = [enum_cls.from_string(e) for e in v]
                            elif isinstance(v, str):
                                v = enum_cls.from_string(v)

                        if v is not None:
                            setattr(self, field.name, v)
        return self

    def to_json(self, indent: Union[None, int, str] = None) -> str:
        """Returns the encoded JSON representation of this message instance."""
        return json.dumps(self.to_dict(), indent=indent)

    def from_json(self: T, value: Union[str, bytes]) -> T:
        """
        Parse the key/value pairs in `value` into this message instance. This
        returns the instance itself and is therefore assignable and chainable.
        """
        return self.from_dict(json.loads(value))


def serialized_on_wire(message: Message) -> bool:
    """
    True if this message was or should be serialized on the wire. This can
    be used to detect presence (e.g. optional wrapper message) and is used
    internally during parsing/serialization.
    """
    return message._serialized_on_wire


def which_one_of(message: Message, group_name: str) -> Tuple[str, Any]:
    """Return the name and value of a message's one-of field group."""
    field = message._group_map.get(group_name)
    if not field:
        return ("", None)
    return (field.name, getattr(message, field.name))


@dataclasses.dataclass
class _Duration(Message):
    # Signed seconds of the span of time. Must be from -315,576,000,000 to
    # +315,576,000,000 inclusive. Note: these bounds are computed from: 60
    # sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
    seconds: int = int64_field(1)
    # Signed fractions of a second at nanosecond resolution of the span of time.
    # Durations less than one second are represented with a 0 `seconds` field and
    # a positive or negative `nanos` field. For durations of one second or more,
    # a non-zero value for the `nanos` field must be of the same sign as the
    # `seconds` field. Must be from -999,999,999 to +999,999,999 inclusive.
    nanos: int = int32_field(2)

    def to_timedelta(self) -> timedelta:
        return timedelta(seconds=self.seconds, microseconds=self.nanos / 1e3)

    @staticmethod
    def delta_to_json(delta: timedelta) -> str:
        parts = str(delta.total_seconds()).split(".")
        if len(parts) > 1:
            while len(parts[1]) not in [3, 6, 9]:
                parts[1] = parts[1] + "0"
        return ".".join(parts) + "s"


@dataclasses.dataclass
class _Timestamp(Message):
    # Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must
    # be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.
    seconds: int = int64_field(1)
    # Non-negative fractions of a second at nanosecond resolution. Negative
    # second values with fractions must still have non-negative nanos values that
    # count forward in time. Must be from 0 to 999,999,999 inclusive.
    nanos: int = int32_field(2)

    def to_datetime(self) -> datetime:
        ts = self.seconds + (self.nanos / 1e9)
        return datetime.fromtimestamp(ts, tz=timezone.utc)

    @staticmethod
    def timestamp_to_json(dt: datetime) -> str:
        nanos = dt.microsecond * 1e3
        copy = dt.replace(microsecond=0, tzinfo=None)
        result = copy.isoformat()
        if (nanos % 1e9) == 0:
            # If there are 0 fractional digits, the fractional
            # point '.' should be omitted when serializing.
            return result + "Z"
        if (nanos % 1e6) == 0:
            # Serialize 3 fractional digits.
            return result + ".%03dZ" % (nanos / 1e6)
        if (nanos % 1e3) == 0:
            # Serialize 6 fractional digits.
            return result + ".%06dZ" % (nanos / 1e3)
        # Serialize 9 fractional digits.
        return result + ".%09dZ" % nanos


class _WrappedMessage(Message):
    """
    Google protobuf wrapper types base class. JSON representation is just the
    value itself.
    """

    value: Any

    def to_dict(self, casing: Casing = Casing.CAMEL) -> Any:
        return self.value

    def from_dict(self: T, value: Any) -> T:
        if value is not None:
            self.value = value
        return self


@dataclasses.dataclass
class _BoolValue(_WrappedMessage):
    value: bool = bool_field(1)


@dataclasses.dataclass
class _Int32Value(_WrappedMessage):
    value: int = int32_field(1)


@dataclasses.dataclass
class _UInt32Value(_WrappedMessage):
    value: int = uint32_field(1)


@dataclasses.dataclass
class _Int64Value(_WrappedMessage):
    value: int = int64_field(1)


@dataclasses.dataclass
class _UInt64Value(_WrappedMessage):
    value: int = uint64_field(1)


@dataclasses.dataclass
class _FloatValue(_WrappedMessage):
    value: float = float_field(1)


@dataclasses.dataclass
class _DoubleValue(_WrappedMessage):
    value: float = double_field(1)


@dataclasses.dataclass
class _StringValue(_WrappedMessage):
    value: str = string_field(1)


@dataclasses.dataclass
class _BytesValue(_WrappedMessage):
    value: bytes = bytes_field(1)


def _get_wrapper(proto_type: str) -> Type:
    """Get the wrapper message class for a wrapped type."""
    return {
        TYPE_BOOL: _BoolValue,
        TYPE_INT32: _Int32Value,
        TYPE_UINT32: _UInt32Value,
        TYPE_INT64: _Int64Value,
        TYPE_UINT64: _UInt64Value,
        TYPE_FLOAT: _FloatValue,
        TYPE_DOUBLE: _DoubleValue,
        TYPE_STRING: _StringValue,
        TYPE_BYTES: _BytesValue,
    }[proto_type]


_Value = Union[str, bytes]
_MetadataLike = Union[Mapping[str, _Value], Collection[Tuple[str, _Value]]]


class ServiceStub(ABC):
    """
    Base class for async gRPC service stubs.
    """

    def __init__(
        self,
        channel: "Channel",
        *,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional[_MetadataLike] = None,
    ) -> None:
        self.channel = channel
        self.timeout = timeout
        self.deadline = deadline
        self.metadata = metadata

    def __resolve_request_kwargs(
        self,
        timeout: Optional[float],
        deadline: Optional["Deadline"],
        metadata: Optional[_MetadataLike],
    ):
        return {
            "timeout": self.timeout if timeout is None else timeout,
            "deadline": self.deadline if deadline is None else deadline,
            "metadata": self.metadata if metadata is None else metadata,
        }

    async def _unary_unary(
        self,
        route: str,
        request: "IProtoMessage",
        response_type: Type[T],
        *,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional[_MetadataLike] = None,
    ) -> T:
        """Make a unary request and return the response."""
        async with self.channel.request(
            route,
            grpclib.const.Cardinality.UNARY_UNARY,
            type(request),
            response_type,
            **self.__resolve_request_kwargs(timeout, deadline, metadata),
        ) as stream:
            await stream.send_message(request, end=True)
            response = await stream.recv_message()
            assert response is not None
            return response

    async def _unary_stream(
        self,
        route: str,
        request: "IProtoMessage",
        response_type: Type[T],
        *,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional[_MetadataLike] = None,
    ) -> AsyncGenerator[T, None]:
        """Make a unary request and return the stream response iterator."""
        async with self.channel.request(
            route,
            grpclib.const.Cardinality.UNARY_STREAM,
            type(request),
            response_type,
            **self.__resolve_request_kwargs(timeout, deadline, metadata),
        ) as stream:
            await stream.send_message(request, end=True)
            async for message in stream:
                yield message
html/modules.html0000664000175000017500000001575413743770170014311 0ustar priesgopriesgo neofox — Neofox 0.4.0.dev1 documentation
html/neofox.html0000664000175000017500000004516113743770170014132 0ustar priesgopriesgo Neofox package — Neofox 0.4.0.dev1 documentation

Neofox package

Submodules

neofox.annotator module

class neofox.annotator.NeoantigenAnnotator(references: neofox.references.references.ReferenceFolder, configuration: neofox.references.references.DependenciesConfiguration)[source]

Bases: object

get_annotation(neoantigen: neofox.model.neoantigen.Neoantigen, patient: neofox.model.neoantigen.Patient)neofox.model.neoantigen.NeoantigenAnnotations[source]

Calculate new epitope features and add to dictonary that stores all properties

neofox.exceptions module

exception neofox.exceptions.NeofoxCommandException[source]

Bases: ValueError

exception neofox.exceptions.NeofoxConfigurationException[source]

Bases: ValueError

exception neofox.exceptions.NeofoxDataValidationException[source]

Bases: ValueError

exception neofox.exceptions.NeofoxInputParametersException[source]

Bases: ValueError

exception neofox.exceptions.NeofoxReferenceException[source]

Bases: ValueError

neofox.neofox module

class neofox.neofox.NeoFox(neoantigens: List[neofox.model.neoantigen.Neoantigen], patient_id: str, patients: List[neofox.model.neoantigen.Patient], num_cpus: int, work_folder=None, output_prefix=None, reference_folder: neofox.references.references.ReferenceFolder = None, configuration: neofox.references.references.DependenciesConfiguration = None)[source]

Bases: object

static annotate_neoantigen(neoantigen: neofox.model.neoantigen.Neoantigen, patient: neofox.model.neoantigen.Patient, reference_folder: neofox.references.references.ReferenceFolder, configuration: neofox.references.references.DependenciesConfiguration)[source]
get_annotations() → List[neofox.model.neoantigen.NeoantigenAnnotations][source]

Loads epitope data (if file has been not imported to R; colnames need to be changed), adds data to class that are needed to calculate, calls epitope class –> determination of epitope properties, write to txt file

Module contents

html/neofox.model.html0000664000175000017500000023131113743770170015223 0ustar priesgopriesgo neofox.model package — Neofox 0.4.0.dev1 documentation

neofox.model package

Submodules

neofox.model.conversion module

class neofox.model.conversion.ModelConverter[source]

Bases: object

GENES_BY_MOLECULE = {<Mhc2Name.DR: 0>: [<Mhc2GeneName.DRB1: 0>], <Mhc2Name.DP: 1>: [<Mhc2GeneName.DPA1: 1>, <Mhc2GeneName.DPB1: 2>], <Mhc2Name.DQ: 2>: [<Mhc2GeneName.DQA1: 3>, <Mhc2GeneName.DQB1: 4>]}
HLA_ALLELE_PATTERN = re.compile('(?:HLA-)?([A-Z0-9]+)[\\*|_]?([0-9]{2}):?([0-9]{2,}):?([0-9]{2,})?:?([0-9]{2,})?([N|L|S|Q]{0,1})')
HLA_DR_MOLECULE_PATTERN = re.compile('(?:HLA-)?(DRB1[\\*|_]?[0-9]{2,}:?[0-9]{2,})')
HLA_MOLECULE_PATTERN = re.compile('(?:HLA-)?([A-Z0-9]+[\\*|_]?[0-9]{2,}:?[0-9]{2,})-([A-Z0-9]+[\\*|_]?[0-9]{2,}:?[0-9]{2,})')
static annotations2short_wide_table(neoantigen_annotations: List[neofox.model.neoantigen.NeoantigenAnnotations], neoantigens: List[neofox.model.neoantigen.Neoantigen]) → pandas.core.frame.DataFrame[source]
static annotations2tall_skinny_table(neoantigen_annotations: List[neofox.model.neoantigen.NeoantigenAnnotations]) → pandas.core.frame.DataFrame[source]
static get_mhc2_isoform_name(a: neofox.model.neoantigen.MhcAllele, b: neofox.model.neoantigen.MhcAllele)[source]
static neoantigens_csv2object(series: pandas.core.series.Series)neofox.model.neoantigen.Neoantigen[source]

transforms an entry from a CSV into an object

static neoantigens_csv2objects(dataframe: pandas.core.frame.DataFrame) → List[neofox.model.neoantigen.Neoantigen][source]

transforms an patients CSV into a list of objects

static object2flat_dict(model: betterproto.Message) → dict[source]

Transforms a model object into a flat dict. Nested fields are concatenated with a dot

static object2series(model_object: betterproto.Message) → pandas.core.series.Series[source]
Parameters

model_object – object of subclass of betterproto.Message

static objects2dataframe(model_objects: List[betterproto.Message]) → pandas.core.frame.DataFrame[source]
Parameters

model_objects – list of objects of subclass of betterproto.Message

static objects2json(model_objects: List[betterproto.Message], output_file: str)[source]
Parameters

model_objects – list of objects of subclass of betterproto.Message

static parse_candidate_file(candidate_file: str, patient_id: str = None) → List[neofox.model.neoantigen.Neoantigen][source]
Parameters
  • candidate_file – the path to an neoantigen candidate input file

  • patient_id – the patient identifier for all neoantigens in the input file, if not provided it is

expected as column named patient.id or patient :return neoantigens in model objects

static parse_mhc1_alleles(alleles: List[str]) → List[neofox.model.neoantigen.Mhc1][source]
static parse_mhc2_alleles(alleles: List[str]) → List[neofox.model.neoantigen.Mhc2][source]
static parse_mhc_allele(allele: str)neofox.model.neoantigen.MhcAllele[source]
static parse_neoantigens_file(neoantigens_file: str) → List[neofox.model.neoantigen.Neoantigen][source]
Parameters

neoantigens_file – the file to neoantigens data CSV file

Returns

the parsed CSV into model objects

static parse_patients_file(patients_file: str) → List[neofox.model.neoantigen.Patient][source]
Parameters

patients_file – the file to patients data CSV file

Returns

the parsed CSV into model objects

static patient_metadata_csv2objects(dataframe: pandas.core.frame.DataFrame) → List[neofox.model.neoantigen.Patient][source]

transforms an patients CSV into a list of objects

neofox.model.neoantigen module

class neofox.model.neoantigen.Annotation(name: str = <betterproto._PLACEHOLDER object>, value: str = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*This is a generic class to hold annotations from Neofox

name: str = <betterproto._PLACEHOLDER object>
value: str = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Mhc1(name: Mhc1Name = <betterproto._PLACEHOLDER object>, zygosity: Zygosity = <betterproto._PLACEHOLDER object>, alleles: List[MhcAllele] = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*Models MHC I alleles related to the same MHC I gene, i.e. 2 alleles/2 isoforms per gene

alleles: List[neofox.model.neoantigen.MhcAllele] = <betterproto._PLACEHOLDER object>
name: neofox.model.neoantigen.Mhc1Name = <betterproto._PLACEHOLDER object>
zygosity: neofox.model.neoantigen.Zygosity = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Mhc1Name(value)[source]

Bases: betterproto.Enum

*Valid names for MHC I classic genes

A = 0
B = 1
C = 2
class neofox.model.neoantigen.Mhc2(name: Mhc2Name = <betterproto._PLACEHOLDER object>, genes: List[Mhc2Gene] = <betterproto._PLACEHOLDER object>, isoforms: List[Mhc2Isoform] = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*Models MHC II alleles related to the same MHC II protein, i.e. 4 isoforms related to 2 genes with 2 alleles each

genes: List[neofox.model.neoantigen.Mhc2Gene] = <betterproto._PLACEHOLDER object>
isoforms: List[neofox.model.neoantigen.Mhc2Isoform] = <betterproto._PLACEHOLDER object>
name: neofox.model.neoantigen.Mhc2Name = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Mhc2Gene(name: Mhc2GeneName = <betterproto._PLACEHOLDER object>, zygosity: Zygosity = <betterproto._PLACEHOLDER object>, alleles: List[MhcAllele] = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*MHC II gene

alleles: List[neofox.model.neoantigen.MhcAllele] = <betterproto._PLACEHOLDER object>
name: neofox.model.neoantigen.Mhc2GeneName = <betterproto._PLACEHOLDER object>
zygosity: neofox.model.neoantigen.Zygosity = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Mhc2GeneName(value)[source]

Bases: betterproto.Enum

*Valid names for MHC II classic genes.DRA is not included in this list as it does not have much variability in the population and for our purpose isconsidered constant.

DPA1 = 1
DPB1 = 2
DQA1 = 3
DQB1 = 4
DRB1 = 0
class neofox.model.neoantigen.Mhc2Isoform(name: str = <betterproto._PLACEHOLDER object>, alpha_chain: MhcAllele = <betterproto._PLACEHOLDER object>, beta_chain: MhcAllele = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*MHC II isoform

alpha_chain: neofox.model.neoantigen.MhcAllele = <betterproto._PLACEHOLDER object>
beta_chain: neofox.model.neoantigen.MhcAllele = <betterproto._PLACEHOLDER object>
name: str = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Mhc2Name(value)[source]

Bases: betterproto.Enum

*Valid names for MHC II classic molecules

DP = 1
DQ = 2
DR = 0
class neofox.model.neoantigen.MhcAllele(full_name: str = <betterproto._PLACEHOLDER object>, name: str = <betterproto._PLACEHOLDER object>, gene: str = <betterproto._PLACEHOLDER object>, group: str = <betterproto._PLACEHOLDER object>, protein: str = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*MHC allele representation. It does not include non synonymous changes to the sequence, changes in the non coding regionor changes in expression. See http://hla.alleles.org/nomenclature/naming.html for details

full_name: str = <betterproto._PLACEHOLDER object>
gene: str = <betterproto._PLACEHOLDER object>
group: str = <betterproto._PLACEHOLDER object>
name: str = <betterproto._PLACEHOLDER object>
protein: str = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Mutation(position:int=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, wild_type_xmer:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, wild_type_aminoacid:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, mutated_xmer:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, mutated_aminoacid:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, left_flanking_region:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, size_left_flanking_region:int=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, right_flanking_region:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, size_right_flanking_region:int=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>)[source]

Bases: betterproto.Message

left_flanking_region: str = <betterproto._PLACEHOLDER object>
mutated_aminoacid: str = <betterproto._PLACEHOLDER object>
mutated_xmer: str = <betterproto._PLACEHOLDER object>
position: int = <betterproto._PLACEHOLDER object>
right_flanking_region: str = <betterproto._PLACEHOLDER object>
size_left_flanking_region: int = <betterproto._PLACEHOLDER object>
size_right_flanking_region: int = <betterproto._PLACEHOLDER object>
wild_type_aminoacid: str = <betterproto._PLACEHOLDER object>
wild_type_xmer: str = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Neoantigen(identifier: str = <betterproto._PLACEHOLDER object>, patient_identifier: str = <betterproto._PLACEHOLDER object>, transcript: Transcript = <betterproto._PLACEHOLDER object>, mutation: Mutation = <betterproto._PLACEHOLDER object>, clonality_estimation: bool = <betterproto._PLACEHOLDER object>, rna_expression: float = <betterproto._PLACEHOLDER object>, dna_variant_allele_frequency: float = <betterproto._PLACEHOLDER object>, rna_variant_allele_frequency: float = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*A neoantigen minimal definition

clonality_estimation: bool = <betterproto._PLACEHOLDER object>
dna_variant_allele_frequency: float = <betterproto._PLACEHOLDER object>
identifier: str = <betterproto._PLACEHOLDER object>
mutation: neofox.model.neoantigen.Mutation = <betterproto._PLACEHOLDER object>
patient_identifier: str = <betterproto._PLACEHOLDER object>
rna_expression: float = <betterproto._PLACEHOLDER object>
rna_variant_allele_frequency: float = <betterproto._PLACEHOLDER object>
transcript: neofox.model.neoantigen.Transcript = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.NeoantigenAnnotations(neoantigen_identifier: str = <betterproto._PLACEHOLDER object>, annotations: List[Annotation] = <betterproto._PLACEHOLDER object>, annotator: str = <betterproto._PLACEHOLDER object>, annotator_version: str = <betterproto._PLACEHOLDER object>, timestamp: str = <betterproto._PLACEHOLDER object>, resources_hash: str = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*A set of annotations for a neoantigen

annotations: List[neofox.model.neoantigen.Annotation] = <betterproto._PLACEHOLDER object>
annotator: str = <betterproto._PLACEHOLDER object>
annotator_version: str = <betterproto._PLACEHOLDER object>
neoantigen_identifier: str = <betterproto._PLACEHOLDER object>
resources_hash: str = <betterproto._PLACEHOLDER object>
timestamp: str = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Patient(identifier: str = <betterproto._PLACEHOLDER object>, is_rna_available: bool = <betterproto._PLACEHOLDER object>, mhc1: List[Mhc1] = <betterproto._PLACEHOLDER object>, mhc2: List[Mhc2] = <betterproto._PLACEHOLDER object>)[source]

Bases: betterproto.Message

*The metadata required for analysis for a given patient + its patient identifier

identifier: str = <betterproto._PLACEHOLDER object>
is_rna_available: bool = <betterproto._PLACEHOLDER object>
mhc1: List[neofox.model.neoantigen.Mhc1] = <betterproto._PLACEHOLDER object>
mhc2: List[neofox.model.neoantigen.Mhc2] = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Transcript(identifier:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, assembly:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>, gene:str=<betterproto._PLACEHOLDER object at 0x7f55e71c67b8>)[source]

Bases: betterproto.Message

assembly: str = <betterproto._PLACEHOLDER object>
gene: str = <betterproto._PLACEHOLDER object>
identifier: str = <betterproto._PLACEHOLDER object>
class neofox.model.neoantigen.Zygosity(value)[source]

Bases: betterproto.Enum

*The zygosity of a given gene

HEMIZYGOUS = 2
HETEROZYGOUS = 1
HOMOZYGOUS = 0
LOSS = 3

neofox.model.validation module

class neofox.model.validation.ModelValidator[source]

Bases: object

static generate_neoantigen_identifier(neoantigen: neofox.model.neoantigen.Neoantigen) → str[source]
static validate(model: betterproto.Message)[source]
static validate_mhc2_isoform_representation(isoform: neofox.model.neoantigen.Mhc2Isoform)neofox.model.neoantigen.Mhc2Isoform[source]
static validate_mhc_allele_representation(allele: neofox.model.neoantigen.MhcAllele)neofox.model.neoantigen.MhcAllele[source]
static validate_neoantigen(neoantigen: neofox.model.neoantigen.Neoantigen)neofox.model.neoantigen.Neoantigen[source]
static validate_patient(patient: neofox.model.neoantigen.Patient)neofox.model.neoantigen.Patient[source]

neofox.model.wrappers module

class neofox.model.wrappers.AnnotationFactory[source]

Bases: object

static build_annotation(name, value)[source]
neofox.model.wrappers.get_alleles_by_gene(mhc_isoforms: List[neofox.model.neoantigen.Mhc2], gene: neofox.model.neoantigen.Mhc2GeneName) → List[neofox.model.neoantigen.MhcAllele][source]

Module contents

html/objects.inv0000664000175000017500000000721113743770171014110 0ustar priesgopriesgo# Sphinx inventory version 2 # Project: Neofox # Version: # The remainder of this file is compressed using zlib. xڽ][s~ϯuؘӾَsub  8#Rwϩ! d:_d}3"wWge?]UqREA|;qmY| ϝe_YDI,ibkRa[h ^rAVcd7IhA|њk x,G-نe,-?!l;]I+I׭ފ+7MUqwOշkEâ/nno9eCd1NBr/%Y/o,A{?u1&vG9~;0| ù/^ũs%(W9"FN8l2ғYC믞04r).EDD-睈)N]AS#5=9Z Z8ӷUطEgZiqb ly҃#0*=ǃr$̿o$7<]E^;a^\q=,/Col : c_GodA56]Ŗ"':fiq8uEyEiA>6)>?֓1 ڹ䘅,wA;E>08 gje lkr_t%(*/׷_ %|@48/2Z}K,$]0#k&6onTG=b-yČ]JVϛN"~3:\pLti`(}WN^wN{P88Y͂ Y>? 3/`Jc_9ӖM;Qڸ Q SEB047/66f=tʟC4y&Ej6"kEre*ܳNcp[Gmw–װup=Zt(LZi9k m_w, dgX:P s&Ay 9h:`ϥ(*k THSb͝*ײl^>nxk)el[=YV47,GDw#n+y8:ҹ8*"*"k:es]sdJ2,6HX OC*4-dG9;ga-ziv>7W3-FЊOItgX˛=!zx>^/C:mzJqsTP-01nHs߻k6NeXWl=f!!vǡQJ bM.D?@.|ΊŚ8&[k;7jeRjכ!Uyy@u8QQ~C2v\=L׎Uڠ$ n"R?u. .,A}L{t3d365cx[Q{(cVl.tG5My0ǰ+-Җa,?!0F"z prexvH,Q5l Vx7$ĪaBpzH/ 6Λs9a~0ay$'0Jj%<F;եᴰ׀`zyArzp'g]_ɉYYyyDVXdtT$ ǦES1և @&U8uI%@? a4h$3 ̲5M!yx 5ߝL&F0~?τNy~6 kT+ئNt !.Xn n~\U[(Oq,k[K[9H93:9,\s-%c!K_+h)ÒxVvribTGiJksܯЩ3<Ԝ,5(8}0N@^S&C W峬^ !2Tbpՙ1N2Ⱥ Python Module Index — Neofox 0.4.0.dev1 documentation
  • »
  • Python Module Index

html/readme.html0000664000175000017500000005474213743770170014076 0ustar priesgopriesgo NeoFox - NEOantigen Feature tOolboX — Neofox 0.4.0.dev1 documentation

NeoFox - NEOantigen Feature tOolboX

DOI PyPI version

Annotation of mutated peptide sequences (mps) with published neo-epitope descriptors

Published Descriptors:

  • netMHCpan (Jurtz et al, 2017, The Journal of Immunology )

  • netMHCIIpan (Jensen et al, 2018, Immunology )

  • IEDB immunogenicity (Calis et al, 2013, PLoS Comput Biol.)

  • Self-similarity, Conserved vs. Improved Binding (Bjerregaard et al, 2017, Front Immunol.)

  • Priority Score (Bjerregaard et al, 2017, Cancer Immunol Immunother.)

  • DAI (Duan et al., 2014, JEM; Ghorani et al., 2018, Ann Oncol.)

  • Neoantigen Fitness (Luksza et al., 2017, Nature; Balachandran et al, 2017, Nature)

  • Residue-centric presentation score (best_rank) & Patient harmonic Best Rank (PHBR-I/II) (Marty et al, 2017, Cell; Marty et al, 2018, Cell)

  • Classically vs Alternatively Defined Neopitopes & Generator Rate (Rech et al., 2018, Cancer Immunology Research)

  • Tcell_predictor (Besser et al, 2019, Journal for ImmunoTherapy of Cancer)

  • neoag (Smith et al, 2019, Cancer Immunology Research)

  • neoantigen dissimilarity (Richman et al, 2019, Cell Systems)

  • MixMHCpred (Bassani-Sternberg et al., 2017, PLoS Comp Bio; Gfeller, 2018; J Immunol.)

  • MixMHC2pred (Racle et al, 2019, Nat. Biotech. 2019)

  • Vaxrank (Rubinsteyn, 2017, Front Immunol;Wang, 2019, Bioinformatics)

NeoFox Requirements

Required Software/Tools/Dependencies:

  • Python 3.7

  • R 3.6.0

  • BLAST 2.8.1

  • netMHCpan 4.0

  • netMHCIIpan 3.2

  • MixMHCpred 2.0.2

  • MixMHC2pred 1.1.3

Usage from the command line

neofox --model-file/--candidate-file neoantigens.txt --patient-id Ptx --patient-data patient_data.txt --output-folder /path/to/out --output-prefix out_prefix [--with-short-wide-table] [--with-tall-skinny-table] [--with-json] [--num_cpus]

Input data

  • --candidate-file: tab-separated values table with neoantigen candidates represented by long mutated peptide sequences

  • --model-file: tab-separated values table with neoantigens in Neofox model format described in protobuf model

  • --patient-id: patient identifier (optional, this will be used as the patient id for neoantigens without patient)

  • --patient data: a table of tab separated values containing metadata on the patient

NOTE: provide either --candidate-file or --model-file

Example of candidate neoantigens table:

gene    UCSC_transcript transcript_expression   substitution    +-13_AA_(SNV)_/_-15_AA_to_STOP_(INDEL)  [WT]_+-13_AA_(SNV)_/_-15_AA_to_STOP_(INDEL) VAF_in_tumor    VAF_in_RNA
VCAN    uc003kii.3  0.519506894 I547T   DEVLGEPSQDILVTDQTRLEATISPET DEVLGEPSQDILVIDQTRLEATISPET 0.294573643 0.857142857

where:

  • gene is the HGNC gene symbol

  • UCSC_trancript is the UCSC transcript id including the version

  • substitution represents a single aminoacid substitution with single letter aminoacids (eg: I547T)

  • +-13_AA_(SNV)_/_-15_AA_to_STOP_(INDEL) the mutated neoantigen

  • [WT]_+-13_AA_(SNV)_/_-15_AA_to_STOP_(INDEL) the equivalent aminoacid sequence in the normal tissue

  • transcript_expression the transcript expression (optional)

  • VAF_in_tumor variant allele frequency in the DNA (optional)

  • VAF_in_RNA variant allele frequency in the RNA (optional, this will be estimated using the VAF_in_tumor if not available)

Example of Neofox model neoantigens table:

transcript.assembly transcript.gene transcript.identifier   mutation.leftFlankingRegion mutation.mutatedAminoacid   mutation.position   mutation.rightFlankingRegion    mutation.wildTypeAminoacid  patientIdentifier   rnaExpression   rnaVariantAlleleFrequency   dnaVariantAlleleFrequency
hg19    BRCA2   uc003kii.3  AAAAAA  L   935 AAAAA   F   Pt1 4.512   0.4675  0.36103
hg19    BRCA2   uc003kii.3  AAAAAA  M   518 AAAAA   R   Pt2 0.154   0.015404    0.034404
hg19    BRCA2   uc003kii.3  AAAAAA  G   285 AAAAA   K   Pt3 8.841207    0.89387 0.51924

where:

  • transcript.assembly - the assembly of the reference genome (only hg19 is supported)

  • transcript.gene - the HGMC gene symbol

  • transcript.identifier - the UCSC transcript identifier including the version number

  • mutation.leftFlankingRegion - the aminoacids flanking the mutation on the left (in IUPAC one letter symbols)

  • mutation.mutatedAminoacid - the mutated aminoacid (IUPAC 1 or 3 letters respecting casing, eg: A and Ala)

  • mutation.position - the 1 based position of the mutation in the protein

  • mutation.rightFlankingRegion - the aminoacids flanking the mutation on the left (in IUPAC one letter symbols)

  • mutation.wildTypeAminoacid - the wild type aminoacid (IUPAC 1 or 3 letters respecting casing, eg: A and Ala)

  • patientIdentifier - the patient identifier

  • rnaExpression - the transcript RNA expression (optional)

  • rnaVariantAlleleFrequency - the variant allele frequency calculated from the RNA (optional, this will be estimated using the dnaVariantAlleleFrequency if not available)

  • dnaVariantAlleleFrequency - the variant allele frequency calculated from the DNA (optional)

Example of patients data table:

identifier  mhcIAlleles mhcIIAlleles   isRnaAvailable
Pt29    HLA-A*03:01,HLA-A*02:01,HLA-B*07:02 HLA-DRB1*11:04,HLA-DRB1*15:01  True

where:

  • identifier - the patient identifier

  • mhcIAlleles - the list of MHC I alleles in the patient

  • mhcIIAlleles - the list of MHC II alleles in the patient

  • isRnaAvailable - whether RNA was available for the analysis. If true then the VAF_in_RNA field will be used, else VAF_in_DNA will be used. (optional)

Output data

The output data is returned in a short wide tab separated values file (--with-short-wide-table). Optionally, it can be provided in a tall skinny tab separated values file (--with-tall-skinny-table) or in JSON (--with-json).

html/search.html0000664000175000017500000001170613743770171014100 0ustar priesgopriesgo Search — Neofox 0.4.0.dev1 documentation
  • »
  • Search

html/searchindex.js0000664000175000017500000004013513743770171014576 0ustar priesgopriesgoSearch.setIndex({docnames:["api_usage","developer_guide","index","install","models","modules","neofox","neofox.model","readme"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.todo":2,"sphinx.ext.viewcode":1,nbsphinx:3,sphinx:56},filenames:["api_usage.ipynb","developer_guide.rst","index.rst","install.rst","models.rst","modules.rst","neofox.rst","neofox.model.rst","readme.rst"],objects:{"":{neofox:[6,0,0,"-"]},"neofox.annotator":{NeoantigenAnnotator:[6,1,1,""]},"neofox.annotator.NeoantigenAnnotator":{get_annotation:[6,2,1,""]},"neofox.exceptions":{NeofoxCommandException:[6,3,1,""],NeofoxConfigurationException:[6,3,1,""],NeofoxDataValidationException:[6,3,1,""],NeofoxInputParametersException:[6,3,1,""],NeofoxReferenceException:[6,3,1,""]},"neofox.model":{conversion:[7,0,0,"-"],neoantigen:[7,0,0,"-"],validation:[7,0,0,"-"],wrappers:[7,0,0,"-"]},"neofox.model.conversion":{ModelConverter:[7,1,1,""]},"neofox.model.conversion.ModelConverter":{GENES_BY_MOLECULE:[7,4,1,""],HLA_ALLELE_PATTERN:[7,4,1,""],HLA_DR_MOLECULE_PATTERN:[7,4,1,""],HLA_MOLECULE_PATTERN:[7,4,1,""],annotations2short_wide_table:[7,2,1,""],annotations2tall_skinny_table:[7,2,1,""],get_mhc2_isoform_name:[7,2,1,""],neoantigens_csv2object:[7,2,1,""],neoantigens_csv2objects:[7,2,1,""],object2flat_dict:[7,2,1,""],object2series:[7,2,1,""],objects2dataframe:[7,2,1,""],objects2json:[7,2,1,""],parse_candidate_file:[7,2,1,""],parse_mhc1_alleles:[7,2,1,""],parse_mhc2_alleles:[7,2,1,""],parse_mhc_allele:[7,2,1,""],parse_neoantigens_file:[7,2,1,""],parse_patients_file:[7,2,1,""],patient_metadata_csv2objects:[7,2,1,""]},"neofox.model.neoantigen":{Annotation:[7,1,1,""],Mhc1:[7,1,1,""],Mhc1Name:[7,1,1,""],Mhc2:[7,1,1,""],Mhc2Gene:[7,1,1,""],Mhc2GeneName:[7,1,1,""],Mhc2Isoform:[7,1,1,""],Mhc2Name:[7,1,1,""],MhcAllele:[7,1,1,""],Mutation:[7,1,1,""],Neoantigen:[7,1,1,""],NeoantigenAnnotations:[7,1,1,""],Patient:[7,1,1,""],Transcript:[7,1,1,""],Zygosity:[7,1,1,""]},"neofox.model.neoantigen.Annotation":{name:[7,4,1,""],value:[7,4,1,""]},"neofox.model.neoantigen.Mhc1":{alleles:[7,4,1,""],name:[7,4,1,""],zygosity:[7,4,1,""]},"neofox.model.neoantigen.Mhc1Name":{A:[7,4,1,""],B:[7,4,1,""],C:[7,4,1,""]},"neofox.model.neoantigen.Mhc2":{genes:[7,4,1,""],isoforms:[7,4,1,""],name:[7,4,1,""]},"neofox.model.neoantigen.Mhc2Gene":{alleles:[7,4,1,""],name:[7,4,1,""],zygosity:[7,4,1,""]},"neofox.model.neoantigen.Mhc2GeneName":{DPA1:[7,4,1,""],DPB1:[7,4,1,""],DQA1:[7,4,1,""],DQB1:[7,4,1,""],DRB1:[7,4,1,""]},"neofox.model.neoantigen.Mhc2Isoform":{alpha_chain:[7,4,1,""],beta_chain:[7,4,1,""],name:[7,4,1,""]},"neofox.model.neoantigen.Mhc2Name":{DP:[7,4,1,""],DQ:[7,4,1,""],DR:[7,4,1,""]},"neofox.model.neoantigen.MhcAllele":{full_name:[7,4,1,""],gene:[7,4,1,""],group:[7,4,1,""],name:[7,4,1,""],protein:[7,4,1,""]},"neofox.model.neoantigen.Mutation":{left_flanking_region:[7,4,1,""],mutated_aminoacid:[7,4,1,""],mutated_xmer:[7,4,1,""],position:[7,4,1,""],right_flanking_region:[7,4,1,""],size_left_flanking_region:[7,4,1,""],size_right_flanking_region:[7,4,1,""],wild_type_aminoacid:[7,4,1,""],wild_type_xmer:[7,4,1,""]},"neofox.model.neoantigen.Neoantigen":{clonality_estimation:[7,4,1,""],dna_variant_allele_frequency:[7,4,1,""],identifier:[7,4,1,""],mutation:[7,4,1,""],patient_identifier:[7,4,1,""],rna_expression:[7,4,1,""],rna_variant_allele_frequency:[7,4,1,""],transcript:[7,4,1,""]},"neofox.model.neoantigen.NeoantigenAnnotations":{annotations:[7,4,1,""],annotator:[7,4,1,""],annotator_version:[7,4,1,""],neoantigen_identifier:[7,4,1,""],resources_hash:[7,4,1,""],timestamp:[7,4,1,""]},"neofox.model.neoantigen.Patient":{identifier:[7,4,1,""],is_rna_available:[7,4,1,""],mhc1:[7,4,1,""],mhc2:[7,4,1,""]},"neofox.model.neoantigen.Transcript":{assembly:[7,4,1,""],gene:[7,4,1,""],identifier:[7,4,1,""]},"neofox.model.neoantigen.Zygosity":{HEMIZYGOUS:[7,4,1,""],HETEROZYGOUS:[7,4,1,""],HOMOZYGOUS:[7,4,1,""],LOSS:[7,4,1,""]},"neofox.model.validation":{ModelValidator:[7,1,1,""]},"neofox.model.validation.ModelValidator":{generate_neoantigen_identifier:[7,2,1,""],validate:[7,2,1,""],validate_mhc2_isoform_representation:[7,2,1,""],validate_mhc_allele_representation:[7,2,1,""],validate_neoantigen:[7,2,1,""],validate_patient:[7,2,1,""]},"neofox.model.wrappers":{AnnotationFactory:[7,1,1,""],get_alleles_by_gene:[7,5,1,""]},"neofox.model.wrappers.AnnotationFactory":{build_annotation:[7,2,1,""]},"neofox.neofox":{NeoFox:[6,1,1,""]},"neofox.neofox.NeoFox":{annotate_neoantigen:[6,2,1,""],get_annotations:[6,2,1,""]},neofox:{annotator:[6,0,0,"-"],exceptions:[6,0,0,"-"],model:[7,0,0,"-"],neofox:[6,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","exception","Python exception"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:exception","4":"py:attribute","5":"py:function"},terms:{"01434":0,"015404":8,"0322":0,"034404":8,"03n":0,"04n":0,"09596":0,"0x7f55e71c67b8":7,"1007":0,"109":0,"115":0,"116":0,"123":0,"13_aa_":8,"141":0,"142":0,"144":0,"154":8,"15_aa_to_stop_":8,"173":0,"192":0,"201020":0,"2013":8,"2014":8,"2017":8,"2018":8,"2019":8,"20201020225902062657":0,"216":0,"219":0,"269":0,"285":8,"294573643":[0,8],"36103":8,"4384":0,"44529":0,"4675":8,"46855":0,"4915":0,"512":8,"518":8,"51924":8,"519506894":[0,8],"6296":0,"647":0,"818":0,"827":0,"828":0,"829":0,"830":0,"831":0,"832":0,"833":0,"834":0,"835":0,"841207":8,"857142857":[0,8],"874":0,"8787":0,"8897":0,"89387":8,"925":0,"926":0,"927":0,"928":0,"929":0,"935":8,"byte":0,"case":[0,8],"class":[6,7],"default":1,"enum":7,"export":3,"float":7,"import":[0,6],"int":[0,6,7],"long":8,"new":[1,6],"return":[0,7,8],"short":8,"static":[6,7],"true":[0,8],For:3,The:[1,3,7,8],These:3,__init__:0,_bootstrap:0,_placehold:7,_serialized_on_wir:0,aaaaa:8,aaaaaa:8,ab8478a95705:0,abov:3,academ:3,add:6,addannot:0,adn_mhci:0,adn_mhcii:0,ala:8,all:[6,7],allel:[0,4,7,8],alpha_chain:[0,7],alphachain:0,alreadi:0,also:3,altern:8,aminoacid:8,amplitude_mhci_affin:0,amplitude_mhci_affinity_9m:0,analysi:[7,8],ani:1,ann:8,annot:[2,4,5,7,8],annotate_neoantigen:6,annotationfactori:7,annotations2short_wide_t:7,annotations2tall_skinny_t:[0,7],annotations_t:0,annotator_vers:[0,7],apt:3,archiv:3,arg:0,assembl:[0,7,8],attribut:0,attributeerror:0,avail:[3,8],balachandran:8,base:[6,7,8],bassani:8,bdist_wheel:1,been:6,besser:8,best:8,best_affinity_mhci_9mer_allel:0,best_affinity_mhci_9mer_allele_wt:0,best_affinity_mhci_9mer_epitop:0,best_affinity_mhci_9mer_epitope_wt:0,best_affinity_mhci_9mer_position_mut:0,best_affinity_mhci_9mer_scor:0,best_affinity_mhci_9mer_score_wt:0,best_affinity_mhci_allel:0,best_affinity_mhci_allele_wt:0,best_affinity_mhci_epitop:0,best_affinity_mhci_epitope_wt:0,best_affinity_mhci_scor:0,best_affinity_mhci_score_wt:0,best_affinity_mhcii_allel:0,best_affinity_mhcii_allele_wt:0,best_affinity_mhcii_epitop:0,best_affinity_mhcii_epitope_wt:0,best_affinity_mhcii_scor:0,best_affinity_mhcii_score_wt:0,best_rank:8,best_rank_mhci_9mer_allel:0,best_rank_mhci_9mer_allele_wt:0,best_rank_mhci_9mer_epitop:0,best_rank_mhci_9mer_epitope_wt:0,best_rank_mhci_9mer_scor:0,best_rank_mhci_9mer_score_wt:0,best_rank_mhci_scor:0,best_rank_mhci_score_allel:0,best_rank_mhci_score_allele_wt:0,best_rank_mhci_score_epitop:0,best_rank_mhci_score_epitope_wt:0,best_rank_mhci_score_wt:0,best_rank_mhcii_scor:0,best_rank_mhcii_score_allel:0,best_rank_mhcii_score_allele_wt:0,best_rank_mhcii_score_epitop:0,best_rank_mhcii_score_epitope_wt:0,best_rank_mhcii_score_wt:0,beta_chain:[0,7],betachain:0,betterproto:[0,7],bin:3,binari:0,bind:8,bio:8,bioinformat:8,biol:8,biotech:8,bjerregaard:8,blast:[3,8],blastp:2,bool:7,both:1,brca2:8,buffer:4,build:[2,3],build_annot:7,calcul:[6,8],cali:8,call:[0,6],can:[1,3,8],cancer:8,candid:[7,8],candidate_fil:7,caret:3,cased_nam:0,cbs:3,cdn_mhci:0,cdn_mhcii:0,cell:8,centric:8,chang:[0,6,7],classic:[7,8],clonality_estim:7,cluster:0,code:7,colnam:6,column:[1,7],com:3,command:2,common:1,comp:8,compar:1,compil:7,complex:4,comput:8,concaten:7,configur:[1,2,6],conserv:8,constant:7,contain:[1,8],content:[2,5],convers:[0,2,5,6],convert:0,core:7,creat:[1,2],csv:7,dai:8,dai_mhci_affinity_cutoff500nm:0,data:[2,3,6,7],datafram:7,dataset:1,def:0,defin:[0,8],definit:7,depend:[1,2,8],dependenciesconfigur:6,describ:[1,8],descriptor:8,desir:1,detail:[1,7],determin:6,dev1:0,develop:2,devlgepsqdilv:0,devlgepsqdilvidqtrleatispet:[0,8],devlgepsqdilvt:0,devlgepsqdilvtdqtrleatispet:[0,8],dict:7,dictonari:6,differ:1,digit:0,discov:1,dissimilar:8,dissimilarity_mhci_cutoff500nm:0,dist:1,distribut:0,dna:8,dna_variant_allele_frequ:[0,7],dnavariantallelefrequ:[0,8],document:4,doe:7,doparallel:3,dot:7,download:3,dpa1:[0,7],dpb1:[0,7],dqa1:[0,7],dqb1:[0,7],dqtrleatispet:0,dra:7,drb1:[0,7,8],drb1_0101:0,drb1_01_01:0,dtu:3,duan:8,dump:0,each:[0,7],either:8,elaps:0,elif:0,els:[0,8],emploi:4,encod:0,entri:7,env:1,environ:[1,3],epitop:[6,8],equival:8,error:1,estim:8,evalu:1,exampl:8,except:[2,5],execut:3,exist:1,expect:[0,7],explain:3,express:[7,8],expression_mutated_transcript:0,fasta:0,featur:6,field:[7,8],file:[1,3,6,7,8],finish:1,fit:8,flag:3,flank:8,flat:7,folder:[0,1,3,8],follow:[1,3],format:8,frame:[2,7],frequenc:8,from:[0,2,3,7],from_json:0,front:8,ftp:3,full_nam:[0,7],fullnam:0,gain:1,gbm:3,gene:[0,7,8],gener:[7,8],generate_neoantigen_identifi:7,generator_r:0,genes_by_molecul:7,genom:[0,8],get:3,get_alleles_by_gen:7,get_annot:[0,6],get_mhc2_isoform_nam:7,gfeller:8,gfellerlab:3,ggplot2:3,ghorani:8,github:3,given:7,got:0,gov:3,group:[0,7],guid:2,harmon:8,has:[0,6],have:[0,1,7],header:0,healthtech:3,hemizyg:[0,7],heterozyg:[0,7],hg19:[0,8],hgmc:8,hgnc:8,histocompat:4,hla:[0,7,8],hla_allele_pattern:7,hla_dr_molecule_pattern:7,hla_molecule_pattern:7,hold:7,home:0,homo_sapien:0,homozyg:[0,7],host:0,html:7,http:[0,3,7],http_address:0,http_server:0,i547t:8,identifi:[0,7,8],iedb:[0,8],iedb_blast_db:0,iedb_immunogenicity_mhci_cutoff500nm:0,immunogen:8,immunol:8,immunolog:8,immunoth:8,immunotherapi:8,importlib:0,improv:8,improved_binder_mhci:0,includ:[7,8],include_default_valu:0,incompat:0,indel:8,indent:0,indic:[0,3],input:[0,2,4,7],instal:2,instanc:0,instead:0,instruct:2,integr:2,integration_test:1,interpret:3,ipython:0,is_rna_avail:[0,7],isconsid:7,isinst:0,isoform:[0,7],isrnaavail:[0,8],item:0,its:[1,7],iupac:8,jem:8,jensen:8,jetwpx0r9ieiqz2smphkpq:0,journal:8,json:[0,8],jurtz:8,just:1,kwd:0,last:[0,1],lattic:3,left:8,left_flanking_region:[0,7],leftflankingregion:[0,8],letter:8,lib:0,line:2,linux:3,list:[0,6,7,8],listcomp:0,load:[0,1,6],log:2,loss:[0,7],lost:1,luksza:8,mai:[0,3],major:4,make:1,makeblastdb:3,manual:3,map:0,marti:8,memori:1,messag:[0,7],meta:0,metadata:[7,8],mhc1:[0,7],mhc1name:7,mhc2:[0,7],mhc2gene:[0,7],mhc2genenam:[0,7],mhc2isoform:[0,7],mhc2name:[0,7],mhc:[0,4,7,8],mhc_isoform:7,mhcallel:[0,7],mhciallel:8,mhciiallel:8,minim:7,mixmhc2pr:[2,8],mixmhc2pred_best_allel:0,mixmhc2pred_best_peptid:0,mixmhc2pred_best_rank:0,mixmhc2pred_unix:3,mixmhcpr:[2,8],mixmhcpred_best_allel:0,mixmhcpred_best_peptid:0,mixmhcpred_best_rank:0,mixmhcpred_best_scor:0,model:[0,2,5,6,8],model_object:7,modelconvert:[0,7],modelvalid:[0,7],modul:[0,2,5],molecul:7,most:0,mps:8,much:7,mutat:[0,7,8],mutated_aminoacid:[0,7],mutated_xm:7,mutatedaminoacid:[0,8],mutatedxm:0,mutation_not_found_in_proteom:0,name:[0,1,7],nat:8,natur:8,ncbi:3,need:[3,6],nefox:3,neo:8,neoag:8,neoag_immunogen:0,neoantigen:[4,5,6],neoantigen_annot:[0,7],neoantigen_identifi:[0,7],neoantigenannot:[0,6,7],neoantigens_csv2object:7,neoantigens_fil:7,neofox:[1,4],neofox_blastp:3,neofox_instal:0,neofox_logfil:1,neofox_makeblastdb:3,neofox_mixmhc2pr:3,neofox_mixmhcpr:3,neofox_netmhc2pan:3,neofox_netmhcpan:3,neofox_rscript:3,neofoxcommandexcept:6,neofoxconfigurationexcept:6,neofoxdatavalidationexcept:6,neofoxinputparametersexcept:6,neofoxreferenceexcept:6,neopitop:8,nest:7,netmhc2pan:2,netmhc2pan_available_allel:0,netmhciipan:[3,8],netmhcpan:[2,8],netmhcpan_available_allel:0,nih:3,nlm:3,node:0,nomenclatur:7,non:7,none:[0,6,7],nonetyp:0,normal:8,normalis:0,note:8,num_cpu:[0,6,8],number:8,number_of_mismatches_mchi:0,numpi:0,object2flat_dict:7,object2seri:7,object:[0,6,7],objects2datafram:7,objects2json:7,oncol:8,one:8,onli:8,option:[1,8],org:7,other:3,otherwis:1,our:7,out:8,out_prefix:8,output:[0,1,2,4],output_fil:7,output_prefix:6,output_previ:1,output_yyyymmddhhmmss:1,over:1,overwritten:1,p123:0,packag:[0,2,5],panda:7,paramet:7,pars:[0,7],parse_candidate_fil:7,parse_mhc1_allel:[0,7],parse_mhc2_allel:[0,7],parse_mhc_allel:7,parse_neoantigens_fil:7,parse_patients_fil:7,parti:2,path:[7,8],pathogensimiliarity_mhci_affinity_9m:0,patient:[2,6,7,8],patient_data:8,patient_id:[0,6,7],patient_identifi:[0,7],patient_metadata_csv2object:7,patientidentifi:[0,8],patients_fil:7,peptid:[3,8],per:7,perhap:0,phbr:[0,8],php:3,phr:0,pin:0,pip:[1,3],plo:8,pog:0,point:[1,3],popul:7,port:0,posit:[0,7,8],prefix:8,preinstal:3,present:8,priesgo:0,print:0,prioriti:8,priority_scor:0,program:1,programmat:2,properti:6,protein:[0,7,8],proteome_db:0,proto_typ:0,protobuf:8,protocol:4,provid:[7,8],psd:0,psi:0,psq:0,pt1:8,pt29:8,pt2:8,pt3:8,ptx:8,publish:8,purpos:7,pwd:3,pyobject:0,python3:0,python:[1,3,8],racl:8,rank:8,rate:8,readm:3,real:1,recent:0,rech:8,recognition_potential_mhci_affinity_9m:0,refer:[0,2,6,8],reference_data_5:0,reference_fold:6,referencefold:6,regionor:7,regress:2,relat:7,relev:1,repres:8,represent:[0,7],requir:[2,3,7],research:8,residu:8,resourc:[0,1],resources_hash:[0,7],respect:8,richman:8,right_flanking_region:[0,7],rightflankingregion:[0,8],rna:8,rna_express:[0,7],rna_variant_allele_frequ:[0,7],rnaexpress:[0,8],rnavariantallelefrequ:[0,8],rscript:3,rubinsteyn:8,run:[2,3],runtimewarn:0,same:[1,7],score:8,second:[0,1],section:1,see:[3,7],self:[0,8],selfsimilarity_mhci_conserved_bind:0,separ:8,sequenc:[7,8],seri:7,server:0,servic:3,set:[1,3,7],setup:1,shell:3,should:3,similar:8,singl:8,site:0,size:0,size_left_flanking_region:7,size_right_flanking_region:7,sizeleftflankingregion:0,sizerightflankingregion:0,skinni:8,smith:8,snv:8,softwar:[3,8],some:[1,3],sourc:[6,7],sqdilvidqtrleat:0,sqdilvtdqtrleat:0,src:0,standard:1,start:0,sternberg:8,store:6,str:[0,6,7],subclass:7,submodul:[2,5],subpackag:[2,5],substitut:8,sudo:3,support:8,sure:1,symbol:8,synonym:7,system:8,tab:8,tabl:8,take:1,tall:8,tar:3,tcell_predictor:8,tcell_predictor_score_cutoff500nm:0,tcsh:3,test:[2,3],test_neofox:1,thei:1,them:[0,1],thi:[0,1,3,7,8],third:2,time:[0,1],timestamp:[0,7],tissu:8,to_dict:0,to_json:0,tool:8,traceback:0,transcript:[0,7,8],transcript_express:8,transform:[2,7],txt:[0,1,6,8],type:8,ubuntu:3,uc003kii:[0,8],ucsc:8,ucsc_trancript:8,ucsc_transcript:8,ufunc:0,under:1,union:0,unit:2,unit_test:1,unittest:1,unless:3,untest:3,usag:2,use:0,used:8,user:3,userwarn:0,using:8,usr:0,vaf_in_dna:8,vaf_in_rna:8,vaf_in_tumor:8,valid:[2,5,6],validate_mhc2_isoform_represent:7,validate_mhc_allele_represent:7,validate_neoantigen:[0,7],validate_pati:[0,7],validated_neoantigen:0,validated_pati:0,valu:[0,1,7,8],valueerror:6,variabl:[1,3,7],variant:8,vaxrank:8,vaxrank_binding_scor:0,vaxrank_total_scor:0,vcan:[0,8],venv:0,version:[3,8],vidqtrlea:0,vtdqtrlea:0,wang:8,were:3,wget:3,wheel:1,where:8,whether:[1,8],which:3,whl:1,whole:1,wide:8,wild:8,wild_type_aminoacid:[0,7],wild_type_xm:7,wildtypeaminoacid:[0,8],wildtypexm:0,without:8,work:3,work_fold:6,wrapper:[2,5,6],write:[1,6],written:1,www:3,x64:3,xvf:3,yet:3,you:[0,1,3],your:3,zygos:[0,7]},titles:["Programmatic usage","Developer guide","NeoFox - NEOantigen Feature tOolboX","Installation instructions","Data models","neofox","Neofox package","neofox.model package","NeoFox - NEOantigen Feature tOolboX"],titleterms:{annot:[0,6],blastp:3,build:1,command:8,configur:3,content:[6,7],convers:7,creat:0,data:[0,4,8],depend:3,develop:1,except:6,featur:[2,8],frame:0,from:8,guid:1,input:8,instal:[1,3],instruct:3,integr:1,line:8,log:1,mixmhc2pr:3,mixmhcpr:3,model:[4,7],modul:[6,7],neoantigen:[0,2,7,8],neofox:[0,2,3,5,6,7,8],netmhc2pan:3,netmhcpan:3,output:8,packag:[1,6,7],parti:3,patient:0,programmat:0,refer:3,regress:1,requir:8,run:[0,1],submodul:[6,7],subpackag:6,test:1,third:3,toolbox:[2,8],transform:0,unit:1,usag:[0,8],valid:[0,7],wrapper:7}})html/_sources/0000775000175000017500000000000013743770170013561 5ustar priesgopriesgohtml/_sources/neofox.rst.txt0000664000175000017500000000120113743767042016425 0ustar priesgopriesgoNeofox package ============== Subpackages ----------- .. toctree:: :maxdepth: 4 neofox.model Submodules ---------- neofox.annotator module ----------------------- .. automodule:: neofox.annotator :members: :undoc-members: :show-inheritance: neofox.exceptions module ------------------------ .. automodule:: neofox.exceptions :members: :undoc-members: :show-inheritance: neofox.neofox module -------------------- .. automodule:: neofox.neofox :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: neofox :members: :undoc-members: :show-inheritance: html/_sources/readme.rst.txt0000664000175000017500000000003613743640326016364 0ustar priesgopriesgo.. mdinclude:: ../../README.mdhtml/_sources/neofox.model.rst.txt0000664000175000017500000000145013743765256017537 0ustar priesgopriesgoneofox.model package ==================== Submodules ---------- neofox.model.conversion module ------------------------------ .. automodule:: neofox.model.conversion :members: :undoc-members: :show-inheritance: neofox.model.neoantigen module ------------------------------ .. automodule:: neofox.model.neoantigen :members: :undoc-members: :show-inheritance: neofox.model.validation module ------------------------------ .. automodule:: neofox.model.validation :members: :undoc-members: :show-inheritance: neofox.model.wrappers module ---------------------------- .. automodule:: neofox.model.wrappers :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: neofox.model :members: :undoc-members: :show-inheritance: html/_sources/index.rst.txt0000664000175000017500000000064013743767042016244 0ustar priesgopriesgo.. Neofox documentation master file, created by sphinx-quickstart on Tue Oct 20 14:56:01 2020. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. NeoFox - NEOantigen Feature tOolboX =================================== .. toctree:: :maxdepth: 4 :caption: Contents: readme install developer_guide models api_usage neofox html/_sources/developer_guide.rst.txt0000664000175000017500000000004213743655565020301 0ustar priesgopriesgo.. mdinclude:: ../../CONTRIBUTE.mdhtml/_sources/install.rst.txt0000664000175000017500000000003713743640326016576 0ustar priesgopriesgo.. mdinclude:: ../../INSTALL.mdhtml/_sources/api_usage.ipynb.txt0000664000175000017500000014204313743655725017413 0ustar priesgopriesgo{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Programmatic usage" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "from neofox.model.conversion import ModelConverter\n", "from neofox.model.validation import ModelValidator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a neoantigen" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "from neofox.model.neoantigen import Neoantigen, Transcript, Mutation" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [], "source": [ "transcript = Transcript(assembly=\"hg19\", gene=\"VCAN\", identifier=\"uc003kii.3\")\n", "mutation = Mutation(position=1007, wild_type_aminoacid=\"I\", mutated_aminoacid=\"T\", left_flanking_region=\"DEVLGEPSQDILV\", right_flanking_region=\"DQTRLEATISPET\")\n", "neoantigen = Neoantigen(transcript=transcript, mutation=mutation, patient_identifier=\"P123\", rna_expression=0.519506894, rna_variant_allele_frequency=0.857142857, dna_variant_allele_frequency=0.294573643)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Validate a neoantigen" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"identifier\": \"jETwpX0R9iEiQz2SMpHkPQ==\",\n", " \"patientIdentifier\": \"P123\",\n", " \"transcript\": {\n", " \"identifier\": \"uc003kii.3\",\n", " \"assembly\": \"hg19\",\n", " \"gene\": \"VCAN\"\n", " },\n", " \"mutation\": {\n", " \"position\": 1007,\n", " \"wildTypeXmer\": \"DEVLGEPSQDILVIDQTRLEATISPET\",\n", " \"wildTypeAminoacid\": \"I\",\n", " \"mutatedXmer\": \"DEVLGEPSQDILVTDQTRLEATISPET\",\n", " \"mutatedAminoacid\": \"T\",\n", " \"leftFlankingRegion\": \"DEVLGEPSQDILV\",\n", " \"sizeLeftFlankingRegion\": 13,\n", " \"rightFlankingRegion\": \"DQTRLEATISPET\",\n", " \"sizeRightFlankingRegion\": 13\n", " },\n", " \"rnaExpression\": 0.519506894,\n", " \"dnaVariantAlleleFrequency\": 0.294573643,\n", " \"rnaVariantAlleleFrequency\": 0.857142857\n", "}\n" ] } ], "source": [ "validated_neoantigen = ModelValidator.validate_neoantigen(neoantigen=neoantigen)\n", "print(validated_neoantigen.to_json(indent=2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a patient" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "from neofox.model.neoantigen import Patient" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# define the MHC I alleles of the patient and parse them into the object representation\n", "mhc1 = ModelConverter.parse_mhc1_alleles([\"HLA-A*01:01:02:03N\", \"HLA-A*01:02:02:03N\", \"HLA-B*01:01:02:03N\", \"HLA-B*01:01:02:04N\", \"HLA-C*01:01\"])" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"zygosity\": \"HETEROZYGOUS\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-A*01:01:02:03N\",\n", " \"name\": \"HLA-A*01:01\",\n", " \"gene\": \"A\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " },\n", " {\n", " \"fullName\": \"HLA-A*01:02:02:03N\",\n", " \"name\": \"HLA-A*01:02\",\n", " \"gene\": \"A\",\n", " \"group\": \"01\",\n", " \"protein\": \"02\"\n", " }\n", " ]\n", "}\n" ] } ], "source": [ "# MHC allele names will be normalised into 4 digits names\n", "print(mhc1[0].to_json(indent=2))" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "# define the MHC II alleles of the patient and parse them into the object representation\n", "mhc2 = ModelConverter.parse_mhc2_alleles([\"HLA-DPA1*01:01\", \"HLA-DPA1*01:02\", \"HLA-DPB1*01:01\", \"HLA-DPB1*01:01\", \"HLA-DRB1*01:01\", \"HLA-DRB1*01:01\"])" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'NoneType' object has no attribute '_serialized_on_wire'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmhc2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_json\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindent\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/src/addannot/venv/lib/python3.6/site-packages/betterproto/__init__.py\u001b[0m in \u001b[0;36mto_json\u001b[0;34m(self, indent)\u001b[0m\n\u001b[1;32m 925\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mto_json\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mindent\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mUnion\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 926\u001b[0m \u001b[0;34m\"\"\"Returns the encoded JSON representation of this message instance.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 927\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mjson\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdumps\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mindent\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mindent\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 928\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 929\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mfrom_json\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mT\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mUnion\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbytes\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mT\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/src/addannot/venv/lib/python3.6/site-packages/betterproto/__init__.py\u001b[0m in \u001b[0;36mto_dict\u001b[0;34m(self, casing, include_default_values)\u001b[0m\n\u001b[1;32m 827\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 828\u001b[0m \u001b[0;31m# Convert each item.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 829\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasing\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 830\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mv\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 831\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcased_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/src/addannot/venv/lib/python3.6/site-packages/betterproto/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 827\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 828\u001b[0m \u001b[0;31m# Convert each item.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 829\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasing\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 830\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mv\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 831\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcased_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/src/addannot/venv/lib/python3.6/site-packages/betterproto/__init__.py\u001b[0m in \u001b[0;36mto_dict\u001b[0;34m(self, casing, include_default_values)\u001b[0m\n\u001b[1;32m 831\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcased_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 832\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 833\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_serialized_on_wire\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 834\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mcased_name\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcasing\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minclude_default_values\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 835\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmeta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mproto_type\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"map\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute '_serialized_on_wire'" ] } ], "source": [ "print(mhc2[0].to_json(indent=2))" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Mhc2(name=, genes=[Mhc2Gene(name=, zygosity=, alleles=[MhcAllele(full_name='HLA-DRB1*01:01', name='HLA-DRB1*01:01', gene='DRB1', group='01', protein='01')])], isoforms=[Mhc2Isoform(name='HLA-DRB1*01:01', alpha_chain=None, beta_chain=MhcAllele(full_name='HLA-DRB1*01:01', name='HLA-DRB1*01:01', gene='DRB1', group='01', protein='01'))])" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mhc2[0]" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "patient = Patient(identifier=\"P123\", is_rna_available=True, mhc1=mhc1, mhc2=mhc2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Validate a patient" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "from neofox.model.validation import ModelValidator" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "validated_patient = ModelValidator.validate_patient(patient)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run Neofox" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject\n", " return f(*args, **kwds)\n", "/usr/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject\n", " return f(*args, **kwds)\n", "/usr/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject\n", " return f(*args, **kwds)\n" ] } ], "source": [ "from neofox.neofox import NeoFox" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[I 201020 22:58:59 neofox:80] Loading data...\n", "/home/priesgo/src/addannot/venv/lib/python3.6/site-packages/distributed/node.py:173: UserWarning: Port 8787 is already in use.\n", "Perhaps you already have a cluster running?\n", "Hosting the HTTP server on port 46855 instead\n", " http_address[\"port\"], self.http_server.port\n", "[I 201020 22:59:00 references:141] Reference genome folder: /home/priesgo/neofox_install/reference_data_5\n", "[I 201020 22:59:00 references:142] Resources\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/netmhc2pan_available_alleles.txt\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/netmhcpan_available_alleles.txt\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/Homo_sapiens.fa\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb/IEDB.fasta\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb/iedb_blast_db.phr\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb/iedb_blast_db.pin\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/iedb/iedb_blast_db.psq\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/Homo_sapiens.fa\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.phr\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.pin\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.pog\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.psd\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.psi\n", "[I 201020 22:59:00 references:144] /home/priesgo/neofox_install/reference_data_5/proteome_db/homo_sapiens.psq\n", "[I 201020 22:59:00 neofox:69] Data loaded\n", "[I 201020 22:59:00 neofox:109] Starting NeoFox annotations...\n", "[D 201020 22:59:00 neofox:115] Neoantigen: {\n", " \"identifier\": \"jETwpX0R9iEiQz2SMpHkPQ==\",\n", " \"patientIdentifier\": \"P123\",\n", " \"transcript\": {\n", " \"identifier\": \"uc003kii.3\",\n", " \"assembly\": \"hg19\",\n", " \"gene\": \"VCAN\"\n", " },\n", " \"mutation\": {\n", " \"position\": 1007,\n", " \"wildTypeXmer\": \"DEVLGEPSQDILVIDQTRLEATISPET\",\n", " \"wildTypeAminoacid\": \"I\",\n", " \"mutatedXmer\": \"DEVLGEPSQDILVTDQTRLEATISPET\",\n", " \"mutatedAminoacid\": \"T\",\n", " \"leftFlankingRegion\": \"DEVLGEPSQDILV\",\n", " \"sizeLeftFlankingRegion\": 13,\n", " \"rightFlankingRegion\": \"DQTRLEATISPET\",\n", " \"sizeRightFlankingRegion\": 13\n", " },\n", " \"rnaExpression\": 0.519506894,\n", " \"dnaVariantAlleleFrequency\": 0.294573643,\n", " \"rnaVariantAlleleFrequency\": 0.857142857\n", " }\n", "[D 201020 22:59:00 neofox:116] Patient: {\n", " \"identifier\": \"P123\",\n", " \"isRnaAvailable\": true,\n", " \"mhc1\": [\n", " {\n", " \"zygosity\": \"HETEROZYGOUS\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-A*01:01:02:03N\",\n", " \"name\": \"HLA-A*01:01\",\n", " \"gene\": \"A\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " },\n", " {\n", " \"fullName\": \"HLA-A*01:02:02:03N\",\n", " \"name\": \"HLA-A*01:02\",\n", " \"gene\": \"A\",\n", " \"group\": \"01\",\n", " \"protein\": \"02\"\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"B\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-B*01:01:02:04N\",\n", " \"name\": \"HLA-B*01:01\",\n", " \"gene\": \"B\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"C\",\n", " \"zygosity\": \"HEMIZYGOUS\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-C*01:01\",\n", " \"name\": \"HLA-C*01:01\",\n", " \"gene\": \"C\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " ]\n", " }\n", " ],\n", " \"mhc2\": [\n", " {\n", " \"genes\": [\n", " {\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-DRB1*01:01\",\n", " \"name\": \"HLA-DRB1*01:01\",\n", " \"gene\": \"DRB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " ]\n", " }\n", " ],\n", " \"isoforms\": [\n", " {\n", " \"name\": \"HLA-DRB1*01:01\",\n", " \"betaChain\": {\n", " \"fullName\": \"HLA-DRB1*01:01\",\n", " \"name\": \"HLA-DRB1*01:01\",\n", " \"gene\": \"DRB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"DP\",\n", " \"genes\": [\n", " {\n", " \"name\": \"DPA1\",\n", " \"zygosity\": \"HETEROZYGOUS\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-DPA1*01:01\",\n", " \"name\": \"HLA-DPA1*01:01\",\n", " \"gene\": \"DPA1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " },\n", " {\n", " \"fullName\": \"HLA-DPA1*01:02\",\n", " \"name\": \"HLA-DPA1*01:02\",\n", " \"gene\": \"DPA1\",\n", " \"group\": \"01\",\n", " \"protein\": \"02\"\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"DPB1\",\n", " \"alleles\": [\n", " {\n", " \"fullName\": \"HLA-DPB1*01:01\",\n", " \"name\": \"HLA-DPB1*01:01\",\n", " \"gene\": \"DPB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " ]\n", " }\n", " ],\n", " \"isoforms\": [\n", " {\n", " \"name\": \"HLA-DPA1*01:01-DPB1*01:01\",\n", " \"alphaChain\": {\n", " \"fullName\": \"HLA-DPA1*01:01\",\n", " \"name\": \"HLA-DPA1*01:01\",\n", " \"gene\": \"DPA1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " },\n", " \"betaChain\": {\n", " \"fullName\": \"HLA-DPB1*01:01\",\n", " \"name\": \"HLA-DPB1*01:01\",\n", " \"gene\": \"DPB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " },\n", " {\n", " \"name\": \"HLA-DPA1*01:02-DPB1*01:01\",\n", " \"alphaChain\": {\n", " \"fullName\": \"HLA-DPA1*01:02\",\n", " \"name\": \"HLA-DPA1*01:02\",\n", " \"gene\": \"DPA1\",\n", " \"group\": \"01\",\n", " \"protein\": \"02\"\n", " },\n", " \"betaChain\": {\n", " \"fullName\": \"HLA-DPB1*01:01\",\n", " \"name\": \"HLA-DPB1*01:01\",\n", " \"gene\": \"DPB1\",\n", " \"group\": \"01\",\n", " \"protein\": \"01\"\n", " }\n", " }\n", " ]\n", " },\n", " {\n", " \"name\": \"DQ\",\n", " \"genes\": [\n", " {\n", " \"name\": \"DQA1\",\n", " \"zygosity\": \"LOSS\"\n", " },\n", " {\n", " \"name\": \"DQB1\",\n", " \"zygosity\": \"LOSS\"\n", " }\n", " ]\n", " }\n", " ]\n", " }\n", "[I 201020 22:59:07 neofox:123] Elapsed time for annotating 1 neoantigens 7 seconds\n" ] } ], "source": [ "annotations = NeoFox(neoantigens=[validated_neoantigen], patients=[validated_patient], patient_id=\"P123\", num_cpus=2).get_annotations()" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[NeoantigenAnnotations(neoantigen_identifier='jETwpX0R9iEiQz2SMpHkPQ==', annotations=[Annotation(name='Expression_mutated_transcript', value='0.44529'), Annotation(name='mutation_not_found_in_proteome', value='1'), Annotation(name='Best_rank_MHCI_score', value='0.4384'), Annotation(name='Best_rank_MHCI_score_epitope', value='VTDQTRLEA'), Annotation(name='Best_rank_MHCI_score_allele', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_score', value='874.8'), Annotation(name='Best_affinity_MHCI_epitope', value='VTDQTRLEA'), Annotation(name='Best_affinity_MHCI_allele', value='HLA-A*01:01'), Annotation(name='Best_rank_MHCI_9mer_score', value='0.4384'), Annotation(name='Best_rank_MHCI_9mer_epitope', value='VTDQTRLEA'), Annotation(name='Best_rank_MHCI_9mer_allele', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_9mer_score', value='874.8'), Annotation(name='Best_affinity_MHCI_9mer_allele', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_9mer_epitope', value='VTDQTRLEA'), Annotation(name='Best_affinity_MHCI_score_WT', value='6296.8'), Annotation(name='Best_affinity_MHCI_epitope_WT', value='VIDQTRLEA'), Annotation(name='Best_affinity_MHCI_allele_WT', value='HLA-A*01:01'), Annotation(name='Best_rank_MHCI_score_WT', value='1.8897'), Annotation(name='Best_rank_MHCI_score_epitope_WT', value='VIDQTRLEA'), Annotation(name='Best_rank_MHCI_score_allele_WT', value='HLA-A*01:01'), Annotation(name='Best_rank_MHCI_9mer_score_WT', value='1.8897'), Annotation(name='Best_rank_MHCI_9mer_epitope_WT', value='VIDQTRLEA'), Annotation(name='Best_rank_MHCI_9mer_allele_WT', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_9mer_score_WT', value='6296.8'), Annotation(name='Best_affinity_MHCI_9mer_allele_WT', value='HLA-A*01:01'), Annotation(name='Best_affinity_MHCI_9mer_epitope_WT', value='VIDQTRLEA'), Annotation(name='Generator_rate', value='0'), Annotation(name='PHBR-I', value='NA'), Annotation(name='Best_affinity_MHCI_9mer_position_mutation', value='2'), Annotation(name='Best_rank_MHCII_score', value='65'), Annotation(name='Best_rank_MHCII_score_epitope', value='SQDILVTDQTRLEAT'), Annotation(name='Best_rank_MHCII_score_allele', value='DRB1_0101'), Annotation(name='Best_affinity_MHCII_score', value='647.81'), Annotation(name='Best_affinity_MHCII_epitope', value='SQDILVTDQTRLEAT'), Annotation(name='Best_affinity_MHCII_allele', value='DRB1_0101'), Annotation(name='Best_rank_MHCII_score_WT', value='46'), Annotation(name='Best_rank_MHCII_score_epitope_WT', value='SQDILVIDQTRLEAT'), Annotation(name='Best_rank_MHCII_score_allele_WT', value='DRB1_0101'), Annotation(name='Best_affinity_MHCII_score_WT', value='269.19'), Annotation(name='Best_affinity_MHCII_epitope_WT', value='SQDILVIDQTRLEAT'), Annotation(name='Best_affinity_MHCII_allele_WT', value='DRB1_0101'), Annotation(name='PHBR-II', value='NA'), Annotation(name='Amplitude_MHCI_affinity_9mer', value='2.4915'), Annotation(name='Amplitude_MHCI_affinity', value='2.4915'), Annotation(name='Pathogensimiliarity_MHCI_affinity_9mer', value='0'), Annotation(name='Recognition_Potential_MHCI_affinity_9mer', value='NA'), Annotation(name='DAI_MHCI_affinity_cutoff500nM', value='NA'), Annotation(name='CDN_MHCI', value='0'), Annotation(name='ADN_MHCI', value='0'), Annotation(name='CDN_MHCII', value='0'), Annotation(name='ADN_MHCII', value='0'), Annotation(name='Tcell_predictor_score_cutoff500nM', value='NA'), Annotation(name='Improved_Binder_MHCI', value='1'), Annotation(name='Selfsimilarity_MHCI_conserved_binder', value='NA'), Annotation(name='Number_of_mismatches_MCHI', value='1'), Annotation(name='Priority_score', value='0.09596'), Annotation(name='Neoag_immunogenicity', value='NA'), Annotation(name='IEDB_Immunogenicity_MHCI_cutoff500nM', value='NA'), Annotation(name='MixMHCpred_best_peptide', value='NA'), Annotation(name='MixMHCpred_best_score', value='NA'), Annotation(name='MixMHCpred_best_rank', value='NA'), Annotation(name='MixMHCpred_best_allele', value='NA'), Annotation(name='MixMHC2pred_best_peptide', value='DEVLGEPSQDILVT'), Annotation(name='MixMHC2pred_best_rank', value='2.818'), Annotation(name='MixMHC2pred_best_allele', value='DRB1_01_01'), Annotation(name='Dissimilarity_MHCI_cutoff500nM', value='NA'), Annotation(name='vaxrank_binding_score', value='0.0322'), Annotation(name='vaxrank_total_score', value='0.01434')], annotator='Neofox', annotator_version='0.4.0.dev1', timestamp='20201020225902062657', resources_hash='')]" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "annotations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Transform the annotations into a data frame" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [], "source": [ "annotations_ts = ModelConverter.annotations2tall_skinny_table(neoantigen_annotations=annotations)" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namevalueneoantigen_identifier
0Expression_mutated_transcript0.44529jETwpX0R9iEiQz2SMpHkPQ==
1mutation_not_found_in_proteome1jETwpX0R9iEiQz2SMpHkPQ==
2Best_rank_MHCI_score0.4384jETwpX0R9iEiQz2SMpHkPQ==
3Best_rank_MHCI_score_epitopeVTDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
4Best_rank_MHCI_score_alleleHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
5Best_affinity_MHCI_score874.8jETwpX0R9iEiQz2SMpHkPQ==
6Best_affinity_MHCI_epitopeVTDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
7Best_affinity_MHCI_alleleHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
8Best_rank_MHCI_9mer_score0.4384jETwpX0R9iEiQz2SMpHkPQ==
9Best_rank_MHCI_9mer_epitopeVTDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
10Best_rank_MHCI_9mer_alleleHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
11Best_affinity_MHCI_9mer_score874.8jETwpX0R9iEiQz2SMpHkPQ==
12Best_affinity_MHCI_9mer_alleleHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
13Best_affinity_MHCI_9mer_epitopeVTDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
14Best_affinity_MHCI_score_WT6296.8jETwpX0R9iEiQz2SMpHkPQ==
15Best_affinity_MHCI_epitope_WTVIDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
16Best_affinity_MHCI_allele_WTHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
17Best_rank_MHCI_score_WT1.8897jETwpX0R9iEiQz2SMpHkPQ==
18Best_rank_MHCI_score_epitope_WTVIDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
19Best_rank_MHCI_score_allele_WTHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
20Best_rank_MHCI_9mer_score_WT1.8897jETwpX0R9iEiQz2SMpHkPQ==
21Best_rank_MHCI_9mer_epitope_WTVIDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
22Best_rank_MHCI_9mer_allele_WTHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
23Best_affinity_MHCI_9mer_score_WT6296.8jETwpX0R9iEiQz2SMpHkPQ==
24Best_affinity_MHCI_9mer_allele_WTHLA-A*01:01jETwpX0R9iEiQz2SMpHkPQ==
25Best_affinity_MHCI_9mer_epitope_WTVIDQTRLEAjETwpX0R9iEiQz2SMpHkPQ==
26Generator_rate0jETwpX0R9iEiQz2SMpHkPQ==
28Best_affinity_MHCI_9mer_position_mutation2jETwpX0R9iEiQz2SMpHkPQ==
29Best_rank_MHCII_score65jETwpX0R9iEiQz2SMpHkPQ==
30Best_rank_MHCII_score_epitopeSQDILVTDQTRLEATjETwpX0R9iEiQz2SMpHkPQ==
31Best_rank_MHCII_score_alleleDRB1_0101jETwpX0R9iEiQz2SMpHkPQ==
32Best_affinity_MHCII_score647.81jETwpX0R9iEiQz2SMpHkPQ==
33Best_affinity_MHCII_epitopeSQDILVTDQTRLEATjETwpX0R9iEiQz2SMpHkPQ==
34Best_affinity_MHCII_alleleDRB1_0101jETwpX0R9iEiQz2SMpHkPQ==
35Best_rank_MHCII_score_WT46jETwpX0R9iEiQz2SMpHkPQ==
36Best_rank_MHCII_score_epitope_WTSQDILVIDQTRLEATjETwpX0R9iEiQz2SMpHkPQ==
37Best_rank_MHCII_score_allele_WTDRB1_0101jETwpX0R9iEiQz2SMpHkPQ==
38Best_affinity_MHCII_score_WT269.19jETwpX0R9iEiQz2SMpHkPQ==
39Best_affinity_MHCII_epitope_WTSQDILVIDQTRLEATjETwpX0R9iEiQz2SMpHkPQ==
40Best_affinity_MHCII_allele_WTDRB1_0101jETwpX0R9iEiQz2SMpHkPQ==
42Amplitude_MHCI_affinity_9mer2.4915jETwpX0R9iEiQz2SMpHkPQ==
43Amplitude_MHCI_affinity2.4915jETwpX0R9iEiQz2SMpHkPQ==
44Pathogensimiliarity_MHCI_affinity_9mer0jETwpX0R9iEiQz2SMpHkPQ==
47CDN_MHCI0jETwpX0R9iEiQz2SMpHkPQ==
48ADN_MHCI0jETwpX0R9iEiQz2SMpHkPQ==
49CDN_MHCII0jETwpX0R9iEiQz2SMpHkPQ==
50ADN_MHCII0jETwpX0R9iEiQz2SMpHkPQ==
52Improved_Binder_MHCI1jETwpX0R9iEiQz2SMpHkPQ==
54Number_of_mismatches_MCHI1jETwpX0R9iEiQz2SMpHkPQ==
55Priority_score0.09596jETwpX0R9iEiQz2SMpHkPQ==
62MixMHC2pred_best_peptideDEVLGEPSQDILVTjETwpX0R9iEiQz2SMpHkPQ==
63MixMHC2pred_best_rank2.818jETwpX0R9iEiQz2SMpHkPQ==
64MixMHC2pred_best_alleleDRB1_01_01jETwpX0R9iEiQz2SMpHkPQ==
66vaxrank_binding_score0.0322jETwpX0R9iEiQz2SMpHkPQ==
67vaxrank_total_score0.01434jETwpX0R9iEiQz2SMpHkPQ==
\n", "
" ], "text/plain": [ " name value neoantigen_identifier\n", "0 Expression_mutated_transcript 0.44529 jETwpX0R9iEiQz2SMpHkPQ==\n", "1 mutation_not_found_in_proteome 1 jETwpX0R9iEiQz2SMpHkPQ==\n", "2 Best_rank_MHCI_score 0.4384 jETwpX0R9iEiQz2SMpHkPQ==\n", "3 Best_rank_MHCI_score_epitope VTDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "4 Best_rank_MHCI_score_allele HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "5 Best_affinity_MHCI_score 874.8 jETwpX0R9iEiQz2SMpHkPQ==\n", "6 Best_affinity_MHCI_epitope VTDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "7 Best_affinity_MHCI_allele HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "8 Best_rank_MHCI_9mer_score 0.4384 jETwpX0R9iEiQz2SMpHkPQ==\n", "9 Best_rank_MHCI_9mer_epitope VTDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "10 Best_rank_MHCI_9mer_allele HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "11 Best_affinity_MHCI_9mer_score 874.8 jETwpX0R9iEiQz2SMpHkPQ==\n", "12 Best_affinity_MHCI_9mer_allele HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "13 Best_affinity_MHCI_9mer_epitope VTDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "14 Best_affinity_MHCI_score_WT 6296.8 jETwpX0R9iEiQz2SMpHkPQ==\n", "15 Best_affinity_MHCI_epitope_WT VIDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "16 Best_affinity_MHCI_allele_WT HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "17 Best_rank_MHCI_score_WT 1.8897 jETwpX0R9iEiQz2SMpHkPQ==\n", "18 Best_rank_MHCI_score_epitope_WT VIDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "19 Best_rank_MHCI_score_allele_WT HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "20 Best_rank_MHCI_9mer_score_WT 1.8897 jETwpX0R9iEiQz2SMpHkPQ==\n", "21 Best_rank_MHCI_9mer_epitope_WT VIDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "22 Best_rank_MHCI_9mer_allele_WT HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "23 Best_affinity_MHCI_9mer_score_WT 6296.8 jETwpX0R9iEiQz2SMpHkPQ==\n", "24 Best_affinity_MHCI_9mer_allele_WT HLA-A*01:01 jETwpX0R9iEiQz2SMpHkPQ==\n", "25 Best_affinity_MHCI_9mer_epitope_WT VIDQTRLEA jETwpX0R9iEiQz2SMpHkPQ==\n", "26 Generator_rate 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "28 Best_affinity_MHCI_9mer_position_mutation 2 jETwpX0R9iEiQz2SMpHkPQ==\n", "29 Best_rank_MHCII_score 65 jETwpX0R9iEiQz2SMpHkPQ==\n", "30 Best_rank_MHCII_score_epitope SQDILVTDQTRLEAT jETwpX0R9iEiQz2SMpHkPQ==\n", "31 Best_rank_MHCII_score_allele DRB1_0101 jETwpX0R9iEiQz2SMpHkPQ==\n", "32 Best_affinity_MHCII_score 647.81 jETwpX0R9iEiQz2SMpHkPQ==\n", "33 Best_affinity_MHCII_epitope SQDILVTDQTRLEAT jETwpX0R9iEiQz2SMpHkPQ==\n", "34 Best_affinity_MHCII_allele DRB1_0101 jETwpX0R9iEiQz2SMpHkPQ==\n", "35 Best_rank_MHCII_score_WT 46 jETwpX0R9iEiQz2SMpHkPQ==\n", "36 Best_rank_MHCII_score_epitope_WT SQDILVIDQTRLEAT jETwpX0R9iEiQz2SMpHkPQ==\n", "37 Best_rank_MHCII_score_allele_WT DRB1_0101 jETwpX0R9iEiQz2SMpHkPQ==\n", "38 Best_affinity_MHCII_score_WT 269.19 jETwpX0R9iEiQz2SMpHkPQ==\n", "39 Best_affinity_MHCII_epitope_WT SQDILVIDQTRLEAT jETwpX0R9iEiQz2SMpHkPQ==\n", "40 Best_affinity_MHCII_allele_WT DRB1_0101 jETwpX0R9iEiQz2SMpHkPQ==\n", "42 Amplitude_MHCI_affinity_9mer 2.4915 jETwpX0R9iEiQz2SMpHkPQ==\n", "43 Amplitude_MHCI_affinity 2.4915 jETwpX0R9iEiQz2SMpHkPQ==\n", "44 Pathogensimiliarity_MHCI_affinity_9mer 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "47 CDN_MHCI 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "48 ADN_MHCI 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "49 CDN_MHCII 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "50 ADN_MHCII 0 jETwpX0R9iEiQz2SMpHkPQ==\n", "52 Improved_Binder_MHCI 1 jETwpX0R9iEiQz2SMpHkPQ==\n", "54 Number_of_mismatches_MCHI 1 jETwpX0R9iEiQz2SMpHkPQ==\n", "55 Priority_score 0.09596 jETwpX0R9iEiQz2SMpHkPQ==\n", "62 MixMHC2pred_best_peptide DEVLGEPSQDILVT jETwpX0R9iEiQz2SMpHkPQ==\n", "63 MixMHC2pred_best_rank 2.818 jETwpX0R9iEiQz2SMpHkPQ==\n", "64 MixMHC2pred_best_allele DRB1_01_01 jETwpX0R9iEiQz2SMpHkPQ==\n", "66 vaxrank_binding_score 0.0322 jETwpX0R9iEiQz2SMpHkPQ==\n", "67 vaxrank_total_score 0.01434 jETwpX0R9iEiQz2SMpHkPQ==" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "annotations_ts" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" } }, "nbformat": 4, "nbformat_minor": 4 } html/_sources/models.rst.txt0000664000175000017500000000047713743654311016422 0ustar priesgopriesgo########### Data models ########### Protocol buffers is employed to model Neofox's input and output data: neoantigens, Major Histocompatibility Complex (MHC) alleles and annotations. .. image:: ../figures/neofox_model.png :width: 800 :alt: Neofox data models `Protocol buffers documentation `_ html/_sources/modules.rst.txt0000664000175000017500000000006713743765256016615 0ustar priesgopriesgoneofox ====== .. toctree:: :maxdepth: 4 neofox html/_static/0000775000175000017500000000000013743770171013366 5ustar priesgopriesgohtml/_static/file.png0000664000175000017500000000043613743556614015022 0ustar priesgopriesgoPNG  IHDRaIDATxR){l ۶f=@ :3~箄rX$AX-D ~ lj(P%8<<9:: PO&$ l~X&EW^4wQ}^ͣ i0/H/@F)Dzq+j[SU5h/oY G&Lfs|{3%U+S`AFIENDB`html/_static/basic.css0000664000175000017500000003250113743770171015162 0ustar priesgopriesgo/* * basic.css * ~~~~~~~~~ * * Sphinx stylesheet -- basic theme. * * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ /* -- main layout ----------------------------------------------------------- */ div.clearer { clear: both; } div.section::after { display: block; content: ''; clear: left; } /* -- relbar ---------------------------------------------------------------- */ div.related { width: 100%; font-size: 90%; } div.related h3 { display: none; } div.related ul { margin: 0; padding: 0 0 0 10px; list-style: none; } div.related li { display: inline; } div.related li.right { float: right; margin-right: 5px; } /* -- sidebar --------------------------------------------------------------- */ div.sphinxsidebarwrapper { padding: 10px 5px 0 10px; } div.sphinxsidebar { float: left; width: 230px; margin-left: -100%; font-size: 90%; word-wrap: break-word; overflow-wrap : break-word; } div.sphinxsidebar ul { list-style: none; } div.sphinxsidebar ul ul, div.sphinxsidebar ul.want-points { margin-left: 20px; list-style: square; } div.sphinxsidebar ul ul { margin-top: 0; margin-bottom: 0; } div.sphinxsidebar form { margin-top: 10px; } div.sphinxsidebar input { border: 1px solid #98dbcc; font-family: sans-serif; font-size: 1em; } div.sphinxsidebar #searchbox form.search { overflow: hidden; } div.sphinxsidebar #searchbox input[type="text"] { float: left; width: 80%; padding: 0.25em; box-sizing: border-box; } div.sphinxsidebar #searchbox input[type="submit"] { float: left; width: 20%; border-left: none; padding: 0.25em; box-sizing: border-box; } img { border: 0; max-width: 100%; } /* -- search page ----------------------------------------------------------- */ ul.search { margin: 10px 0 0 20px; padding: 0; } ul.search li { padding: 5px 0 5px 20px; background-image: url(file.png); background-repeat: no-repeat; background-position: 0 7px; } ul.search li a { font-weight: bold; } ul.search li div.context { color: #888; margin: 2px 0 0 30px; text-align: left; } ul.keywordmatches li.goodmatch a { font-weight: bold; } /* -- index page ------------------------------------------------------------ */ table.contentstable { width: 90%; margin-left: auto; margin-right: auto; } table.contentstable p.biglink { line-height: 150%; } a.biglink { font-size: 1.3em; } span.linkdescr { font-style: italic; padding-top: 5px; font-size: 90%; } /* -- general index --------------------------------------------------------- */ table.indextable { width: 100%; } table.indextable td { text-align: left; vertical-align: top; } table.indextable ul { margin-top: 0; margin-bottom: 0; list-style-type: none; } table.indextable > tbody > tr > td > ul { padding-left: 0em; } table.indextable tr.pcap { height: 10px; } table.indextable tr.cap { margin-top: 10px; background-color: #f2f2f2; } img.toggler { margin-right: 3px; margin-top: 3px; cursor: pointer; } div.modindex-jumpbox { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; margin: 1em 0 1em 0; padding: 0.4em; } div.genindex-jumpbox { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; margin: 1em 0 1em 0; padding: 0.4em; } /* -- domain module index --------------------------------------------------- */ table.modindextable td { padding: 2px; border-collapse: collapse; } /* -- general body styles --------------------------------------------------- */ div.body { min-width: 450px; max-width: 800px; } div.body p, div.body dd, div.body li, div.body blockquote { -moz-hyphens: auto; -ms-hyphens: auto; -webkit-hyphens: auto; hyphens: auto; } a.headerlink { visibility: hidden; } a.brackets:before, span.brackets > a:before{ content: "["; } a.brackets:after, span.brackets > a:after { content: "]"; } h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink, caption:hover > a.headerlink, p.caption:hover > a.headerlink, div.code-block-caption:hover > a.headerlink { visibility: visible; } div.body p.caption { text-align: inherit; } div.body td { text-align: left; } .first { margin-top: 0 !important; } p.rubric { margin-top: 30px; font-weight: bold; } img.align-left, .figure.align-left, object.align-left { clear: left; float: left; margin-right: 1em; } img.align-right, .figure.align-right, object.align-right { clear: right; float: right; margin-left: 1em; } img.align-center, .figure.align-center, object.align-center { display: block; margin-left: auto; margin-right: auto; } img.align-default, .figure.align-default { display: block; margin-left: auto; margin-right: auto; } .align-left { text-align: left; } .align-center { text-align: center; } .align-default { text-align: center; } .align-right { text-align: right; } /* -- sidebars -------------------------------------------------------------- */ div.sidebar { margin: 0 0 0.5em 1em; border: 1px solid #ddb; padding: 7px; background-color: #ffe; width: 40%; float: right; clear: right; overflow-x: auto; } p.sidebar-title { font-weight: bold; } div.admonition, div.topic, blockquote { clear: left; } /* -- topics ---------------------------------------------------------------- */ div.topic { border: 1px solid #ccc; padding: 7px; margin: 10px 0 10px 0; } p.topic-title { font-size: 1.1em; font-weight: bold; margin-top: 10px; } /* -- admonitions ----------------------------------------------------------- */ div.admonition { margin-top: 10px; margin-bottom: 10px; padding: 7px; } div.admonition dt { font-weight: bold; } p.admonition-title { margin: 0px 10px 5px 0px; font-weight: bold; } div.body p.centered { text-align: center; margin-top: 25px; } /* -- content of sidebars/topics/admonitions -------------------------------- */ div.sidebar > :last-child, div.topic > :last-child, div.admonition > :last-child { margin-bottom: 0; } div.sidebar::after, div.topic::after, div.admonition::after, blockquote::after { display: block; content: ''; clear: both; } /* -- tables ---------------------------------------------------------------- */ table.docutils { margin-top: 10px; margin-bottom: 10px; border: 0; border-collapse: collapse; } table.align-center { margin-left: auto; margin-right: auto; } table.align-default { margin-left: auto; margin-right: auto; } table caption span.caption-number { font-style: italic; } table caption span.caption-text { } table.docutils td, table.docutils th { padding: 1px 8px 1px 5px; border-top: 0; border-left: 0; border-right: 0; border-bottom: 1px solid #aaa; } table.footnote td, table.footnote th { border: 0 !important; } th { text-align: left; padding-right: 5px; } table.citation { border-left: solid 1px gray; margin-left: 1px; } table.citation td { border-bottom: none; } th > :first-child, td > :first-child { margin-top: 0px; } th > :last-child, td > :last-child { margin-bottom: 0px; } /* -- figures --------------------------------------------------------------- */ div.figure { margin: 0.5em; padding: 0.5em; } div.figure p.caption { padding: 0.3em; } div.figure p.caption span.caption-number { font-style: italic; } div.figure p.caption span.caption-text { } /* -- field list styles ----------------------------------------------------- */ table.field-list td, table.field-list th { border: 0 !important; } .field-list ul { margin: 0; padding-left: 1em; } .field-list p { margin: 0; } .field-name { -moz-hyphens: manual; -ms-hyphens: manual; -webkit-hyphens: manual; hyphens: manual; } /* -- hlist styles ---------------------------------------------------------- */ table.hlist { margin: 1em 0; } table.hlist td { vertical-align: top; } /* -- other body styles ----------------------------------------------------- */ ol.arabic { list-style: decimal; } ol.loweralpha { list-style: lower-alpha; } ol.upperalpha { list-style: upper-alpha; } ol.lowerroman { list-style: lower-roman; } ol.upperroman { list-style: upper-roman; } :not(li) > ol > li:first-child > :first-child, :not(li) > ul > li:first-child > :first-child { margin-top: 0px; } :not(li) > ol > li:last-child > :last-child, :not(li) > ul > li:last-child > :last-child { margin-bottom: 0px; } ol.simple ol p, ol.simple ul p, ul.simple ol p, ul.simple ul p { margin-top: 0; } ol.simple > li:not(:first-child) > p, ul.simple > li:not(:first-child) > p { margin-top: 0; } ol.simple p, ul.simple p { margin-bottom: 0; } dl.footnote > dt, dl.citation > dt { float: left; margin-right: 0.5em; } dl.footnote > dd, dl.citation > dd { margin-bottom: 0em; } dl.footnote > dd:after, dl.citation > dd:after { content: ""; clear: both; } dl.field-list { display: grid; grid-template-columns: fit-content(30%) auto; } dl.field-list > dt { font-weight: bold; word-break: break-word; padding-left: 0.5em; padding-right: 5px; } dl.field-list > dt:after { content: ":"; } dl.field-list > dd { padding-left: 0.5em; margin-top: 0em; margin-left: 0em; margin-bottom: 0em; } dl { margin-bottom: 15px; } dd > :first-child { margin-top: 0px; } dd ul, dd table { margin-bottom: 10px; } dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } dl > dd:last-child, dl > dd:last-child > :last-child { margin-bottom: 0; } dt:target, span.highlighted { background-color: #fbe54e; } rect.highlighted { fill: #fbe54e; } dl.glossary dt { font-weight: bold; font-size: 1.1em; } .optional { font-size: 1.3em; } .sig-paren { font-size: larger; } .versionmodified { font-style: italic; } .system-message { background-color: #fda; padding: 5px; border: 3px solid red; } .footnote:target { background-color: #ffa; } .line-block { display: block; margin-top: 1em; margin-bottom: 1em; } .line-block .line-block { margin-top: 0; margin-bottom: 0; margin-left: 1.5em; } .guilabel, .menuselection { font-family: sans-serif; } .accelerator { text-decoration: underline; } .classifier { font-style: oblique; } .classifier:before { font-style: normal; margin: 0.5em; content: ":"; } abbr, acronym { border-bottom: dotted 1px; cursor: help; } /* -- code displays --------------------------------------------------------- */ pre { overflow: auto; overflow-y: hidden; /* fixes display issues on Chrome browsers */ } pre, div[class*="highlight-"] { clear: both; } span.pre { -moz-hyphens: none; -ms-hyphens: none; -webkit-hyphens: none; hyphens: none; } div[class*="highlight-"] { margin: 1em 0; } td.linenos pre { border: 0; background-color: transparent; color: #aaa; } table.highlighttable { display: block; } table.highlighttable tbody { display: block; } table.highlighttable tr { display: flex; } table.highlighttable td { margin: 0; padding: 0; } table.highlighttable td.linenos { padding-right: 0.5em; } table.highlighttable td.code { flex: 1; overflow: hidden; } .highlight .hll { display: block; } div.highlight pre, table.highlighttable pre { margin: 0; } div.code-block-caption + div { margin-top: 0; } div.code-block-caption { margin-top: 1em; padding: 2px 5px; font-size: small; } div.code-block-caption code { background-color: transparent; } table.highlighttable td.linenos, div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ user-select: none; } div.code-block-caption span.caption-number { padding: 0.1em 0.3em; font-style: italic; } div.code-block-caption span.caption-text { } div.literal-block-wrapper { margin: 1em 0; } code.descname { background-color: transparent; font-weight: bold; font-size: 1.2em; } code.descclassname { background-color: transparent; } code.xref, a code { background-color: transparent; font-weight: bold; } h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { background-color: transparent; } .viewcode-link { float: right; } .viewcode-back { float: right; font-family: sans-serif; } div.viewcode-block:target { margin: -1px -10px; padding: 0 10px; } /* -- math display ---------------------------------------------------------- */ img.math { vertical-align: middle; } div.body div.math p { text-align: center; } span.eqno { float: right; } span.eqno a.headerlink { position: absolute; z-index: 1; } div.math:hover a.headerlink { visibility: visible; } /* -- printout stylesheet --------------------------------------------------- */ @media print { div.document, div.documentwrapper, div.bodywrapper { margin: 0 !important; width: 100%; } div.sphinxsidebar, div.related, div.footer, #top-link { display: none; } }html/_static/searchtools.js0000664000175000017500000003764013743556614016270 0ustar priesgopriesgo/* * searchtools.js * ~~~~~~~~~~~~~~~~ * * Sphinx JavaScript utilities for the full-text search. * * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ if (!Scorer) { /** * Simple result scoring code. */ var Scorer = { // Implement the following function to further tweak the score for each result // The function takes a result array [filename, title, anchor, descr, score] // and returns the new score. /* score: function(result) { return result[4]; }, */ // query matches the full name of an object objNameMatch: 11, // or matches in the last dotted part of the object name objPartialMatch: 6, // Additive scores depending on the priority of the object objPrio: {0: 15, // used to be importantResults 1: 5, // used to be objectResults 2: -5}, // used to be unimportantResults // Used when the priority is not in the mapping. objPrioDefault: 0, // query found in title title: 15, partialTitle: 7, // query found in terms term: 5, partialTerm: 2 }; } if (!splitQuery) { function splitQuery(query) { return query.split(/\s+/); } } /** * Search Module */ var Search = { _index : null, _queued_query : null, _pulse_status : -1, htmlToText : function(htmlString) { var htmlElement = document.createElement('span'); htmlElement.innerHTML = htmlString; $(htmlElement).find('.headerlink').remove(); docContent = $(htmlElement).find('[role=main]')[0]; if(docContent === undefined) { console.warn("Content block not found. Sphinx search tries to obtain it " + "via '[role=main]'. Could you check your theme or template."); return ""; } return docContent.textContent || docContent.innerText; }, init : function() { var params = $.getQueryParameters(); if (params.q) { var query = params.q[0]; $('input[name="q"]')[0].value = query; this.performSearch(query); } }, loadIndex : function(url) { $.ajax({type: "GET", url: url, data: null, dataType: "script", cache: true, complete: function(jqxhr, textstatus) { if (textstatus != "success") { document.getElementById("searchindexloader").src = url; } }}); }, setIndex : function(index) { var q; this._index = index; if ((q = this._queued_query) !== null) { this._queued_query = null; Search.query(q); } }, hasIndex : function() { return this._index !== null; }, deferQuery : function(query) { this._queued_query = query; }, stopPulse : function() { this._pulse_status = 0; }, startPulse : function() { if (this._pulse_status >= 0) return; function pulse() { var i; Search._pulse_status = (Search._pulse_status + 1) % 4; var dotString = ''; for (i = 0; i < Search._pulse_status; i++) dotString += '.'; Search.dots.text(dotString); if (Search._pulse_status > -1) window.setTimeout(pulse, 500); } pulse(); }, /** * perform a search for something (or wait until index is loaded) */ performSearch : function(query) { // create the required interface elements this.out = $('#search-results'); this.title = $('

' + _('Searching') + '

').appendTo(this.out); this.dots = $('').appendTo(this.title); this.status = $('

 

').appendTo(this.out); this.output = $('